home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / frasrc19.zip / PARSERA.ASM < prev    next >
Assembly Source File  |  1995-03-08  |  98KB  |  2,132 lines

  1.    PAGE          ,132
  2.  
  3. ;    Name: PARSERA.ASM
  4. ;  Author: Chuck Ebbert  CompuServe [76306,1226]
  5. ;                         internet: 76306.1226@compuserve.com
  6.  
  7. ; Fast floating-point routines for Fractint.
  8.  
  9. ;   (c) Copyright 1992-1995 Chuck Ebbert.  All rights reserved.
  10.  
  11. ; This program is an assembler version of the C 'execution engine' part
  12. ;    of Mark Peterson's FRACTINT Formula Parser.  Many of the operator
  13. ;    functions were copied from Mark's code in the files FPU087.ASM
  14. ;    and FPU387.ASM.  The basic operator functions are assembler versions
  15. ;    of the code in PARSER.C.  Many 'combined' operator functions were
  16. ;    added to the program as well.
  17.  
  18. ; As of 31 Decmember 1993 this is also an in-memory compiler.  The code
  19. ;    generator is in PARSERFP.C.  Define the variable COMPILER to
  20. ;    build the compiler, otherwise the interpreter will be built.
  21. ;    COMPILER must also be #defined in PARSERFP.C to build compiler.
  22.  
  23.  
  24. ;    This code may be freely distributed and used in non-commercial
  25. ;    programs provided the author is credited either during program
  26. ;    execution or in the documentation, and this copyright notice
  27. ;    is left intact.  Sale of this code, or its use in any commercial
  28. ;    product requires permission from the author.  Nominal distribution
  29. ;    and handling fees may be charged by shareware and freeware
  30. ;    distributors.
  31.  
  32.  
  33. ;             Date      Init   Change description
  34.  
  35. ;           7 Mar 1995   TIW   Added PWR (0,0) domain check
  36. ;          21 Feb 1995   TIW   Shortened ATanh/ATan for MASM 6 compatibility
  37. ;          21 Feb 1995   CAE   Changes ATan and ATanh
  38.  
  39. ;          15 Feb 1995   CAE   Added safety tests to macros.
  40. ;                              Changed fStkASin, etc. to work with compiler.
  41. ;                              Added fwait to Sto2 function for safety.
  42.  
  43. ;           8 Feb 1995   CAE   Removed transparent3d code.
  44. ;                              Added inversion support (compiler untested.)
  45.  
  46. ;           8 Jan 1995   JCO   Added fStkASin, fStkASinh, fStkACos, fStkACosh,
  47. ;                              fStkATan, fStkATanh, fStkSqrt, fStkCAbs.
  48.  
  49. ;          31 Dec 1994   JCO   Made changes to keep code in line with C code.
  50. ;                              Not necessary, since code isn't called.  Will
  51. ;                              make it easier to make it run later.  Added
  52. ;                              old <- z to end of fform_per_pixel to match
  53. ;                              C code.
  54.  
  55. ;          30 Dec 1993   CAE   Compiler is working
  56. ;                              Changed EXIT_OPER -> ret in 3 operator fns
  57. ;                              Added safety test for fn size in macros
  58.  
  59. ;          12 Dec 1993   CAE   Compiler additions
  60.  
  61. ;           4 Dec 1993   CAE   SinhCosh function accuracy improved
  62. ;                              Added LoadImagAdd/Sub/Mul
  63.  
  64. ;          19 Nov 1993   CAE   Revised macros for compiler mode.
  65.  
  66. ;          10 Nov 1993   CAE   Changed Exp function for more accuracy.
  67.  
  68. ;          06 Nov 93     CAE   Added 'LodRealPwr', 'One', 'ORClr2', 'Sqr3'.
  69. ;                              Revised Pwr function to use regs vs. memory.
  70. ;                              Changed many functions to 'included' type.
  71.  
  72. ;          31 Oct 93     CAE   Added 'Dbl' function.
  73.  
  74. ;          09 Oct 1993   CAE   Changed SinhCosh to use wider range of 387.
  75. ;                              Most FNINITs changed to FINIT.
  76. ;                              Loop logic revised slightly.
  77. ;                              Separated code from parserfp.c's codeseg.
  78. ;                              Added fStkStoClr2, fStkZero and fStkIdent.
  79. ;                              New 'pseudo calctype' fn. fFormulaX added.
  80.  
  81. ;          12 Jul 1993   CAE   Moved BadFormula to PARSER.C.
  82.  
  83.  
  84.    .386                                ; this only works on a 386
  85.    .387                                ;  with a 387
  86.  
  87. ifdef ??version
  88.    masm51
  89.    quirks
  90. endif
  91.  
  92. ARGSZ              equ 16              ; size of complex arg
  93. ;;;ARGSZ              equ 32              ; size of hypercomplex arg
  94. CPFX               equ 4               ; size of constarg prefix
  95. CARG               equ CPFX+ARGSZ      ; size of constarg
  96. LASTSQR            equ CARG*4+CPFX     ; offset of lastsqr from start of v
  97.  
  98. ; ---------------------------------------------------------------------------
  99. FRAME              MACRO regs          ; build a stack frame
  100.       push         bp
  101.       mov          bp, sp
  102.    IRP             reg, <regs>
  103.       push         reg
  104.       ENDM
  105.    ENDM
  106.  
  107. UNFRAME            MACRO regs          ; unframe before return
  108.    IRP             reg, <regs>
  109.       pop          reg
  110.       ENDM
  111.       pop          bp
  112.    ENDM
  113.  
  114. ; ---------------------------------------------------------------------------
  115. ; Pop a number of scalars from the FPU stack.
  116. ; Generate as many 'fcompp' instr.'s as possible.
  117. ; Then a 'fstp st(0)' if needed.
  118. POP_STK            MACRO StkPop
  119.    NumToPop        = StkPop SHR 1
  120.    REPT            NumToPop
  121.       fcompp
  122.       ENDM
  123.    NumToPop        = StkPop - ( NumToPop SHL 1 )
  124.    REPT            NumToPop
  125.       fstp         st(0)
  126.       ENDM
  127.    ENDM
  128.  
  129. ; Uncomment the following line to enable compiler code generation.
  130. ;COMPILER           EQU 1
  131.  
  132. ; ---------------------------------------------------------------------------
  133. ; Generate beginning code for operator fn.
  134. BEGN_OPER          MACRO OperName
  135.    ifndef          COMPILER
  136. ;; only align when no compiler
  137.    align           4
  138.    endif
  139.  
  140. ;; always generate public and begin of proc (before fixups)
  141.    public          _fStk&OperName
  142. _fStk&OperName     proc near
  143.  
  144.    ifdef           COMPILER
  145. ;; generate the fixups for compiler
  146. ;; size of fn. | 8000h to mark it as an OPER instead of an INCL  CAE 27Dec93
  147.       dw           Size_&OperName OR 8000h
  148. ;; near pointer to the start of actual code                      CAE 19Dec93
  149.       dw           offset PARSERA_TEXT:Code_&OperName
  150. ;;    addr of fn to include (undefined if Incl_&OperName==255 below)
  151.       dw           IAddr_&OperName
  152. ;; offset of x fixup or 255 if none
  153.       db           XFixup_&OperName
  154. ;; offset of y fixup or 255 if none
  155.       db           YFixup_&OperName
  156. ;; offset of included(called) fn or 255 if none
  157.       db           Incl_&OperName
  158.  
  159.    endif
  160.  
  161. ;; added label for code begin point                              CAE 25Nov93
  162. Code_&OperName:
  163.  
  164.    ENDM
  165.  
  166. ; ---------------------------------------------------------------------------
  167. END_OPER           MACRO OperName
  168. ; Generate end of operator fn. code.
  169.  
  170.    ifndef          COMPILER
  171. ;; gen a return instr.
  172.       ret
  173.    else
  174.  
  175. ;; gen a jump label
  176. End_&OperName:
  177.  
  178. ;; generate zero for fixups not generated during fn.
  179.  
  180.    ifndef          Incl_&OperName
  181. ;; No included operator. Generate 255 offset, 0 address.          CAE 19Nov93
  182. Incl_&OperName     EQU 255
  183. IAddr_&OperName    EQU 0
  184.    endif
  185.  
  186.    ifndef          XFixup_&OperName
  187. XFixup_&OperName   EQU 255
  188.    endif
  189.  
  190.    ifndef          YFixup_&OperName
  191. YFixup_&OperName   EQU 255
  192.    endif
  193.  
  194.    endif
  195.  
  196. ;; Always gen size of fn (subtract size of header here)
  197. Size_&OperName     EQU $ - Code_&OperName
  198. ;; Make sure fn is of legal size                                  CAE 30DEC93
  199.    .errnz          (Size_&OperName GT 127)
  200.  
  201. ;; and end of procedure.
  202. _fStk&OperName     endp
  203.    ENDM
  204.  
  205. ; ---------------------------------------------------------------------------
  206. BEGN_INCL          MACRO OperName
  207. ;; Generate beginning code for 'included' operator fn.
  208. ;; No fixups allowed in one of these functions.
  209.  
  210. ;; Safety test: generate an equate here so the INCL_OPER          CAE 15Feb95
  211. ;;    macro can test to see if this really is includable.
  212. Is_Incl_&OperName  EQU 1
  213.  
  214. ;; Don't bother with align in compiler mode.
  215.    ifndef          COMPILER
  216.    align           4
  217.    endif
  218.  
  219. ;; Generate public (incl fns. can be called directly) and begin of proc.
  220.    public          _fStk&OperName
  221. _fStk&OperName     proc near
  222.  
  223.    ifdef           COMPILER
  224. ;; Size of included fn.  changed to word                          CAE 27Dec93
  225.       dw           Size_&OperName
  226.    endif
  227.  
  228. ;; added label for code begin point                               CAE 25Nov93
  229. Code_&OperName:
  230.  
  231.    ENDM
  232.  
  233. ; ---------------------------------------------------------------------------
  234. ; Generate end of 'included' operator fn. code.
  235. END_INCL           MACRO OperName
  236.    ifndef          COMPILER
  237. ;; generate return
  238.       ret
  239.    else
  240.  
  241. ;; generate label for jump to end of fn.
  242. End_&OperName:
  243.    endif
  244.  
  245. ;; always generate actual size of fn. (subtract hdr. size)
  246.    Size_&OperName  EQU $ - Code_&OperName
  247. ;; Make sure fn is of legal size                                  CAE 30DEC93
  248.    .errnz          (Size_&OperName GT 127)
  249. ;; always generate end-of-proc
  250. _fStk&OperName     endp
  251.    ENDM
  252.  
  253. ; ---------------------------------------------------------------------------
  254. ; 'Include' a function inside another one
  255. INCL_OPER          MACRO CallingOper,OperToIncl
  256.  
  257. ;; Make sure the included fn was defined with the BEGN_INCL macro.
  258.    ifndef          Is_Incl_&OperToIncl                         ;  CAE 15Feb95
  259.    .error          "Included function was not defined with BEGN_INCL macro"
  260.    endif
  261.  
  262. ;; Gen equate for offset of include in outer fn.
  263. ;; Always generate this to prevent >1 include even when not       CAE 15FEB95
  264. ;;    building the compiler.
  265. Incl_&CallingOper  EQU $ - Code_&CallingOper
  266.    ifdef           COMPILER
  267. ;; Address of included fn.
  268. IAddr_&CallingOper EQU _fStk&OperToIncl
  269. ;; Gen 1 1-byte placeholder for the included fn to make codegen easier
  270.       db           0ffH
  271.    else
  272.  
  273. ;; Generate a call to the included fn.
  274.       call         _fStk&OperToIncl
  275.    endif
  276.    ENDM
  277.  
  278. ; ---------------------------------------------------------------------------
  279. ; Exit early from an operator function.
  280. EXIT_OPER          MACRO FnToExit
  281.    ifdef           COMPILER
  282. ;; jump to end of operator fn
  283.       jmp          short End_&FnToExit
  284.    else
  285.  
  286. ;; return to caller
  287.       ret
  288.    endif
  289.    ENDM
  290.  
  291. ; ---------------------------------------------------------------------------
  292. ; Generate an FPU instruction and a fixup.
  293. ; AddrToFix is = X or Y
  294. FIXUP              MACRO OperName, InstrToFix, Addr
  295.    ifdef           COMPILER
  296.  
  297. ;; Generate a fixup as an offset from start of fn.
  298. ;; Fixup is two bytes into the instruction, thus the '+ 2'.
  299. ;; This may not be true for all instructions.
  300.    ifidni          <Addr>, <X>
  301. XFixup_&OperName   EQU $ - Code_&OperName + 2
  302.    else
  303. ;; assume fixup is for y
  304. YFixup_&OperName   EQU $ - Code_&OperName + 2
  305.    endif
  306. ;; Generate a load, store or whatever of any convenient value using DS.
  307.       &InstrToFix  QWORD PTR ds:_fLastOp
  308.    else
  309.  
  310.    ifidni          <Addr>, <X>
  311. ;; Gen load of X using SI.
  312.       &InstrToFix  QWORD PTR [si]
  313.    else
  314. ;; Assume fixup is for y, use SI+8.
  315.       &InstrToFix  QWORD PTR [si+8]
  316.    endif
  317.    endif
  318.  
  319.    ENDM
  320.  
  321. ; ---------------------------------------------------------------------------
  322. ; Align 4 if no compiler.
  323. PARSALIGN          macro AlignFn
  324.    ifndef          COMPILER
  325.    align           4
  326.    endif
  327.    ENDM
  328.  
  329. ; CAE added macros for common operations Feb 1995
  330.  
  331. GEN_SQR0           macro
  332. ;; square the stack top, don't save magnitude in lastsqr          CAE 15FEB95
  333.       fld          st(0)               ; x x y
  334.       fld          st(0)               ; x x x y
  335.       fmul         st,st(3)            ; xy x x y
  336.       fadd         st,st               ; 2xy x x y
  337.       fxch         st(3)               ; y x x 2xy
  338.       fadd         st(2),st            ; y x x+y 2xy
  339.       fsubp        st(1),st            ; x-y x+y 2xy
  340.       fmulp        st(1),st            ; xx-yy 2xy
  341.       ENDM
  342.  
  343. GEN_SQRT           macro               ;                           CAE 15Feb95
  344.    ; can use a max of 2 regs
  345.       fld          st(1)               ; y x y
  346.       fld          st(1)               ; x y x y
  347.       fpatan                           ; atan x y
  348.       fdiv         __2_                ; theta=atan/2 x y
  349.       fsincos                          ; cos sin x y
  350.       fxch         st(3)               ; y sin x cos
  351.       fmul         st,st(0)            ; yy sin x cos
  352.       fxch         st(2)               ; x sin yy cos
  353.       fmul         st,st(0)            ; xx sin yy cos
  354.       faddp        st(2),st            ; sin xx+yy cos
  355.       fxch         st(2)               ; cos xx+yy sin
  356.       fxch                             ; xx+yy cos sin
  357.       fsqrt                            ; sqrt(xx+yy) cos sin
  358.       fsqrt                            ; mag=sqrt(sqrt(xx+yy)) cos sin
  359.       fmul         st(2),st            ; mag cos mag*sin
  360.       fmulp        st(1),st            ; mag*cos mag*sin
  361.       ENDM
  362. ; ---------------------------------------------------------------------------
  363. ; external functions
  364.    extrn           _invertz2:far
  365.  
  366. ; ---------------------------------------------------------------------------
  367. _DATA              segment word public use16 'DATA'
  368.    extrn           _invert:WORD
  369.    extrn           _maxit:DWORD
  370.    extrn           _inside:WORD
  371.    extrn           _outside:WORD
  372.    extrn           _coloriter:DWORD
  373.    extrn           _kbdcount:WORD      ; keyboard counter
  374.    extrn           _dotmode:WORD
  375.    extrn           __1_:QWORD, _PointFive:QWORD, __2_:QWORD, _infinity:QWORD
  376.    extrn           _LastOp:WORD, _LastInitOp:WORD
  377.    extrn           _InitOpPtr:WORD, _InitStoPtr:WORD, _InitLodPtr:WORD
  378.    extrn           _s:WORD
  379.    extrn           _OpPtr:WORD, _LodPtr:WORD, _StoPtr:WORD
  380.    extrn           _Load:DWORD, _Store:DWORD
  381.    extrn           _FormName:byte
  382.    extrn           _dy1:DWORD, _dx1:DWORD, _dy0:DWORD, _dx0:DWORD
  383.    extrn           _new:WORD, _old:WORD
  384.    extrn           _overflow:WORD
  385.    extrn           _col:WORD, _row:WORD
  386.    extrn           _Arg1:WORD, _Arg2:WORD
  387.    extrn           _f:DWORD, _pfls:DWORD, _v:DWORD
  388.    extrn           _debugflag:WORD
  389. _DATA               ends
  390.  
  391. ; ---------------------------------------------------------------------------
  392.  
  393. _BSS               segment word public use16 'BSS'
  394. _fLastOp           label DWORD         ; save seg, offset of lastop here
  395.       dd           ?
  396. _PtrToZ            label WORD          ; offset of z
  397.       dw           ?
  398. _BSS               ends
  399.  
  400. DGROUP             group _DATA,_BSS
  401.  
  402. ; ---------------------------------------------------------------------------
  403. ; Operator Functions follow.
  404. ; ---------------------------------------------------------------------------
  405.  
  406. ; NOTE: None of these operator functions may change any registers but
  407. ;       ax and si.  The exceptions are those functions that update
  408. ;       the current values of the 'status' regs as needed.
  409.  
  410. ;  On entry to these functions:
  411. ;   FPU stack is used as the evaluation stack.
  412. ;         The FPU stack can overflow into memory.  Accuracy is not lost but
  413. ;         calculations are slower.
  414. ;   es -> DGROUP
  415. ;   ds -> parser data
  416. ;   cx -> lastop
  417. ;   edx == orbit counter (in fFormulaX)
  418. ;   di -> stack overflow area, used by push and pull functions and as
  419. ;         a temporary storage area
  420. ;   bx -> current operator, operand pair
  421. ;    [bx] = operator function address, i.e. addr. of current '_fStkXXX'
  422. ;    [bx+2] = operand pointer or zero if no operand
  423. ;   si = operand pointer (loaded from [bx+2] before call of operator fn.)
  424.  
  425. ; New rules Feb 1993:
  426. ;  1. No EXIT_OPER before an INCL_OPER
  427. ;     (no jumps can be made past an included function.)
  428. ;  2. No included fn may include another, or have any fixups.
  429. ;  3. Only one included fn. allowed per 'normal' fn.
  430.  
  431. ; --------------------------------------------------------------------------
  432.    ;  Put this code in PARSERA_TEXT, not PARSERFP_TEXT           CAE 09OCT93
  433. PARSERA_TEXT     segment para public use16 'CODE'
  434.    ;  Non-standard segment register setup.
  435.    assume         es:DGROUP, ds:nothing, cs:PARSERA_TEXT
  436.  
  437. ; --------------------------------------------------------------------------
  438. ; Included functions must be before any fns that include them.
  439. ; --------------------------------------------------------------------------
  440.    BEGN_INCL       Log                 ; Log
  441.    ; From FPU387.ASM
  442.    ; Log is called by Pwr and is also called directly.
  443.       ftst
  444.       fstsw        ax
  445.       sahf
  446.       jnz          short NotBothZero
  447.       fxch                             ; y x
  448.       ftst
  449.       fstsw        ax
  450.       sahf
  451.       fxch                             ; x y
  452.       jnz          short NotBothZero
  453.       POP_STK      2                   ; clear two numbers
  454.       fldz
  455.       fldz
  456.       mov          ax, 1               ; domain error (1 in ax)
  457.       EXIT_OPER    Log                 ; return (0,0)
  458.    PARSALIGN
  459. NotBothZero:
  460.       xor          ax,ax               ; no domain error (0 in ax)
  461.       fld          st(1)               ; y x y
  462.       fld          st(1)               ; x y x y
  463.       fpatan                           ; z.y x y
  464.       fxch         st(2)               ; y x z.y
  465.       fmul         st,st(0)            ; yy x z.y
  466.       fxch                             ; x yy z.y
  467.       fmul         st,st(0)            ; xx yy z.y
  468.       fadd                             ; mod z.y
  469.       fldln2                           ; ln2, mod, z.y
  470.       fmul         _PointFive          ; ln2/2, mod, z.y
  471.       fxch                             ; mod, ln2/2, z.y
  472.       fyl2x                            ; z.x, z.y
  473.    END_INCL        Log
  474. ; --------------------------------------------------------------------------
  475.    BEGN_INCL       SinhCosh            ; Included fn, Sinh, Cosh of st
  476.    ; From FPU087.ASM with mods to use less registers & for 387.
  477.    ; Mod for 387-only after Fractint v18.                        CAE 09OCT93
  478.    ; NOTE: Full 80-bit accuracy is *NOT* maintained in this function!
  479.    ;       Only 1 additional register can be used here.
  480.    ; Changed fn so that rounding errors are less.                CAE 04DEC93
  481.       fstcw        _Arg2               ; use arg2 to hold CW
  482.       fwait
  483.       fldln2                           ; ln(2) x
  484.       fdivp        st(1),st            ; x/ln(2), start the fdivr instr.
  485.       mov          ax,_Arg2            ; Now do some integer instr.'s
  486.       push         ax                  ; Save control word on stack
  487.       or           ax,0000110000000000b
  488.       mov          _Arg2,ax
  489.       fld          st                  ; x/ln(2), x/ln(2)
  490.       fldcw        _Arg2               ; Now set control to round toward zero
  491.    ; Chop toward zero rounding applies now                        CAE 4DEC93
  492.       frndint                          ; int = integer(x/ln(2)), x/ln(2)
  493.       pop          ax                  ; restore old CW to AX
  494.       mov          _Arg2,ax            ; ...then move it to Arg2
  495.       fldcw        _Arg2               ; Restore control word from Arg2
  496.    ; Normal rounding is in effect again                           CAE 4DEC93
  497.       fxch                             ; x/ln(2), int
  498.       fsub         st,st(1)            ; -1 < rem < 1.0, int
  499.       f2xm1                            ; 2**rem-1, int
  500.       fadd         __1_                ; 2**rem, int
  501.       fscale                           ; e**x, int
  502.       fstp         st(1)               ; e**x
  503.       fld          st                  ; e**x, e**x
  504.       fmul         _PointFive          ; e^x/2 e^x
  505.       fstp         QWORD PTR es:[di]   ; e^x  use overflow stk for temp here
  506.       fdivr        _PointFive          ; e**-x/2
  507.       fld          st                  ; e**-x/2, e**-x/2
  508.       fadd         QWORD PTR es:[di]   ; coshx, e**-x/2
  509.       fxch                             ; e^-x/2, coshx
  510.       fsubr        QWORD PTR es:[di]   ; sinhx, coshx (fsubr pending)
  511.    END_INCL        SinhCosh
  512. ; --------------------------------------------------------------------------
  513.    BEGN_INCL       Ident               ; Ident                   CAE 09OCT93
  514.    END_INCL        Ident
  515. ; --------------------------------------------------------------------------
  516.    BEGN_INCL       Sqr3                ; Sqr3                    CAE 06NOV93
  517.       fmul         st,st(0)            ; Magnitude/sqr of a real# on st
  518.    END_INCL        Sqr3                ; x^2 0 ...
  519. ; --------------------------------------------------------------------------
  520.    BEGN_INCL       Conj                ; Complex conjugate
  521.       fxch                             ; y x ...
  522.       fchs                             ; -y x ...
  523.       fxch                             ; x -y ...
  524.    END_INCL        Conj
  525. ; --------------------------------------------------------------------------
  526.    BEGN_INCL       Conj2               ; Complex conjugate (uses a reg)
  527.       fldz                             ; 0 x y ...               CAE 20Nov93
  528.       fsubrp       st(2),st            ; x -y ...
  529.    END_INCL        Conj2
  530. ; --------------------------------------------------------------------------
  531.    BEGN_INCL       Real                ; Real
  532.       fstp         st(1)               ; x ...
  533.       fldz                             ; 0 x ...
  534.       fxch                             ; x 0 ...
  535.    END_INCL        Real
  536. ; --------------------------------------------------------------------------
  537.    BEGN_INCL       RealFlip            ; Real, flip combined.
  538.       fstp         st(1)               ; y=x ...
  539.       fldz                             ; x=0 y ...
  540.    END_INCL        RealFlip
  541. ; --------------------------------------------------------------------------
  542.    BEGN_INCL       Add                 ; Add
  543.       faddp        st(2),st            ; Arg2->d.x += Arg1->d.x;
  544.       faddp        st(2),st            ; Arg2->d.y += Arg1->d.y;
  545.    END_INCL        Add
  546. ; --------------------------------------------------------------------------
  547.    BEGN_INCL       Sub                 ; Subtract
  548.       fsubp        st(2),st            ; Arg2->d.x -= Arg1->d.x;
  549.       fsubp        st(2),st            ; Arg2->d.y -= Arg1->d.y;
  550.    END_INCL        Sub
  551. ; --------------------------------------------------------------------------
  552.    BEGN_OPER       LodRealAdd          ; Load, Real, Add combined
  553.       FIXUP        LodRealAdd, fadd, X ; Add x-value from memory
  554.    END_OPER        LodRealAdd
  555. ; --------------------------------------------------------------------------
  556.    BEGN_OPER       LodRealSub          ; Load, Real, Subtract combined
  557.       FIXUP        LodRealSub, fsub, X ; (fsub qword ptr X)
  558.    END_OPER        LodRealSub
  559. ; --------------------------------------------------------------------------
  560.    BEGN_OPER       LodImagAdd          ; Load, Imag, Add combined CAE 4DEC93
  561.       FIXUP        LodImagAdd, fadd, Y ; Add x-value from memory
  562.    END_OPER        LodImagAdd
  563. ; --------------------------------------------------------------------------
  564.    BEGN_OPER       LodImagSub          ; Load, Imag, Sub combined CAE 4DEC93
  565.       FIXUP        LodImagSub, fsub, Y ; (fsub qword ptr X)
  566.    END_OPER        LodImagSub
  567. ; --------------------------------------------------------------------------
  568.    BEGN_INCL       Real2               ; Real value (fast version)
  569.       fldz                             ; 0 x y ... (uses a reg)
  570.       fstp         st(2)               ; x 0 ...
  571.    END_INCL        Real2
  572. ; --------------------------------------------------------------------------
  573.    BEGN_OPER       Lod                 ; Load
  574.       FIXUP        Lod, fld, Y         ; y ...
  575.       FIXUP        Lod, fld, X         ; x y ...
  576.    END_OPER        Lod
  577. ; --------------------------------------------------------------------------
  578.    BEGN_INCL       Clr1                ; Clear stack
  579.       finit                            ; changed from fninit     CAE 09OCT93
  580.    END_INCL        Clr1
  581. ; --------------------------------------------------------------------------
  582.    BEGN_INCL       Imag                ; Imaginary value
  583.       POP_STK      1                   ; y
  584.       fldz                             ; 0 y
  585.       fxch                             ; x=y 0
  586.    END_INCL        Imag
  587. ; --------------------------------------------------------------------------
  588.    BEGN_INCL       ImagFlip            ; Imaginary value, flip combined
  589.       POP_STK      1                   ; y ...
  590.       fldz                             ; x=0 y ...
  591.    END_INCL        ImagFlip
  592. ; --------------------------------------------------------------------------
  593.    BEGN_INCL Abs                       ; Absolute value
  594.       fxch
  595.       fabs
  596.       fxch
  597.       fabs
  598.    END_INCL Abs
  599. ; --------------------------------------------------------------------------
  600.    BEGN_OPER       LodRealMul          ; Load, Real, Multiply
  601.       FIXUP        LodRealMul, fld, X  ; y.x x.x x.y
  602.       fmul         st(2),st            ; y.x x.x z.y
  603.       fmul                             ; z.x z.y
  604.    END_OPER        LodRealMul
  605. ; --------------------------------------------------------------------------
  606.    BEGN_OPER       LodImagMul          ; Load, Imag, Multiply     CAE 4DEC93
  607.       FIXUP        LodImagMul, fld, Y  ; y.y x.x x.y
  608.       fmul         st(2),st            ; y.y x.x z.y
  609.       fmul                             ; z.x z.y
  610.    END_OPER        LodImagMul
  611. ; --------------------------------------------------------------------------
  612.    BEGN_INCL       Neg                 ; Negative
  613.       fxch
  614.       fchs                             ; Arg1->d.y = -Arg1->d.y;
  615.       fxch
  616.       fchs
  617.    END_INCL        Neg
  618. ; --------------------------------------------------------------------------
  619.    BEGN_OPER       EndInit             ; End of initialization expr.
  620.    ifndef          COMPILER            ; this instr not needed   CAE 30DEC93
  621.       mov          _LastInitOp,bx      ; LastInitOp=OpPtr
  622.    endif
  623.       finit                            ; changed from fninit     CAE 09OCT93
  624.    END_OPER        EndInit
  625. ; --------------------------------------------------------------------------
  626.    BEGN_OPER       StoClr1             ; Store, clear FPU
  627.       FIXUP        StoClr1, fstp, X    ; y ...
  628.       FIXUP        StoClr1, fst, Y     ; y ...
  629.       finit                            ; use finit, not fninit
  630.    END_OPER        StoClr1
  631. ; --------------------------------------------------------------------------
  632.    BEGN_OPER       StoClr2             ; Store, clear FPU        CAE 09OCT93
  633.       FIXUP        StoClr2, fstp, X    ; y
  634.       FIXUP        StoClr2, fstp, Y    ; <empty> (store pending)
  635.    END_OPER        StoClr2
  636. ; --------------------------------------------------------------------------
  637.    BEGN_OPER       Sto                 ; Store, leave on ST
  638.    ; Revised to do store first, then exchange.                   CAE 10NOV93
  639.       FIXUP        Sto, fst, X
  640.       fxch                             ; y x ...
  641.       FIXUP        Sto, fst, Y
  642.       fxch                             ; x y ...
  643.    END_OPER        Sto
  644. ; --------------------------------------------------------------------------
  645.    BEGN_OPER       Sto2                ; Store, leave on ST (uses a reg)
  646.       fld          st(1)               ; y x y
  647.       FIXUP        Sto2, fstp, Y       ; x y
  648.       FIXUP        Sto2, fst, X
  649.       fwait                            ; CAE added fwait for safety 15Feb95
  650.    END_OPER        Sto2
  651. ; --------------------------------------------------------------------------
  652.    BEGN_OPER       LodReal             ; Load a real
  653.       fldz                             ; 0 ...
  654.       FIXUP        LodReal, fld, X     ; x 0 ...
  655.    END_OPER        LodReal
  656. ; --------------------------------------------------------------------------
  657.    BEGN_OPER       LodRealC            ; Load real const
  658.       fldz                             ; y=0 ...
  659.       FIXUP        LodRealC, fld, X    ; x 0 ...
  660.    END_OPER        LodRealC
  661. ; --------------------------------------------------------------------------
  662.    BEGN_OPER       LodRealFlip         ; Load real, flip
  663.       FIXUP        LodRealFlip, fld, X ; y=x ...
  664.       fldz                             ; x=0 y ...
  665.    END_OPER        LodRealFlip
  666. ; --------------------------------------------------------------------------
  667.    BEGN_OPER       LodRealAbs          ; Load real, abs
  668.       fldz                             ; 0 ...
  669.       FIXUP        LodRealAbs, fld, X  ; x 0 ...
  670.       fabs                             ; x=abs(x) 0 ...
  671.    END_OPER        LodRealAbs
  672. ; --------------------------------------------------------------------------
  673.    BEGN_INCL       Flip                ; Exchange real, imag
  674.       fxch                             ; x=y y=x ...
  675.    END_INCL        Flip
  676. ; --------------------------------------------------------------------------
  677.    BEGN_OPER       LodImag             ; Load, imaginary
  678.       fldz                             ; 0 ...
  679.       FIXUP        LodImag, fld, Y     ; x=y 0
  680.    END_OPER        LodImag
  681. ; --------------------------------------------------------------------------
  682.    BEGN_OPER       LodImagFlip         ; Load, imaginary, flip
  683.       FIXUP        LodImagFlip, fld, Y ; y ...
  684.       fldz                             ; 0 y ...
  685.    END_OPER        LodImagFlip
  686. ; --------------------------------------------------------------------------
  687.    BEGN_OPER       LodImagAbs          ; Load, imaginary, absolute value
  688.       fldz                             ; 0 ...
  689.       FIXUP        LodImagAbs, fld, Y  ; x=y 0 ...
  690.       fabs                             ; x=abs(y) 0 ...
  691.    END_OPER        LodImagAbs
  692. ; --------------------------------------------------------------------------
  693.    BEGN_OPER       LodConj             ; Load, conjugate
  694.       FIXUP        LodConj, fld, Y     ; y ...
  695.       fchs                             ; y=-y ...
  696.       FIXUP        LodConj, fld, X     ; x y ...
  697.    END_OPER        LodConj
  698. ; --------------------------------------------------------------------------
  699.    BEGN_OPER       LodAdd              ; Load, Add (uses a reg)
  700.       FIXUP        LodAdd, fadd, X
  701.       FIXUP        LodAdd, fld, Y
  702.       faddp        st(2),st
  703.    END_OPER        LodAdd
  704. ; --------------------------------------------------------------------------
  705.    BEGN_OPER       LodSub              ; Load, Subtract (uses a reg)
  706.       FIXUP        LodSub, fsub, X
  707.       FIXUP        LodSub, fld, Y
  708.       fsubp        st(2),st
  709.    END_OPER        LodSub
  710. ; --------------------------------------------------------------------------
  711.    BEGN_OPER       StoDup              ; Store, duplicate top operand
  712.       FIXUP        StoDup, fst, X      ; x y
  713.       fld          st(1)               ; y x y
  714.       FIXUP        StoDup, fst, Y      ; y x y
  715.       fld          st(1)               ; x y x y
  716.    END_OPER        StoDup
  717. ; --------------------------------------------------------------------------
  718.    BEGN_OPER       StoDbl              ; Store, double (uses a reg)
  719.       FIXUP        StoDbl, fst, X      ; x y (store x)
  720.       fadd         st,st               ; 2x y
  721.       fld          st(1)               ; y 2x y
  722.       FIXUP        StoDbl, fst, Y      ; y 2x y (store y)
  723.       faddp        st(2),st            ; 2x 2y
  724.    END_OPER        StoDbl
  725. ; --------------------------------------------------------------------------
  726.    BEGN_INCL       Zero                ; Zero                    CAE 09OCT93
  727.       POP_STK      2                   ; ...
  728.       fldz                             ; 0 ...
  729.       fldz                             ; 0 0 ...
  730.    END_INCL        Zero
  731. ; --------------------------------------------------------------------------
  732.    BEGN_INCL       One                 ; One                     CAE 06NOV93
  733.       POP_STK      2                   ; ...
  734.       fldz                             ; 0 ...
  735.       fld1                             ; 1 0 ...
  736.    END_INCL        One
  737. ; --------------------------------------------------------------------------
  738.    BEGN_OPER       LodSubMod           ; Load, Subtract, Mod
  739.       FIXUP        LodSubMod, fsub, X  ; x.x-y.x  x.y  ...
  740.       fmul         st,st               ; sqr(x.x-y.x) x.y ...
  741.       fldz                             ; 0 sqrx x.y ...
  742.       fxch         st(2)               ; x.y sqrx 0 ...
  743.       FIXUP        LodSubMod, fsub, Y  ; x.y-y.y sqrx 0 ...
  744.       fmul         st,st               ; sqry sqrx 0 ...
  745.       fadd                             ; mod 0
  746.    END_OPER        LodSubMod
  747. ; --------------------------------------------------------------------------
  748.    BEGN_INCL       Sqr                 ; Square, save magnitude in LastSqr
  749.       fld          st(0)               ; x x y
  750.       fmul         st(1),st            ; x x*x y
  751.       fmul         st,st(2)            ; xy xx y
  752.       mov          si, WORD PTR _v     ; si -> variables
  753.       fadd         st,st(0)            ; 2xy xx y
  754.       fxch         st(2)               ; y xx 2xy
  755.       fmul         st,st(0)            ; yy xx 2xy
  756.       fld          st(1)               ; xx yy xx 2xy
  757.       fadd         st,st(1)            ; xx+yy yy xx 2xy
  758.       fstp         QWORD PTR [si+LASTSQR] ; yy xx 2xy
  759.       fsubp        st(1),st            ; xx-yy 2xy
  760.    END_INCL        Sqr
  761. ; --------------------------------------------------------------------------
  762.    BEGN_INCL       Sqr0                ; Square, don't save magnitude
  763.        GEN_SQR0
  764.    END_INCL        Sqr0
  765. ; --------------------------------------------------------------------------
  766.    BEGN_INCL       Mul                 ; Multiply
  767.    ; From FPU087.ASM
  768.       fld          st(1)               ; y.y, y.x, y.y, x.x, x.y
  769.       fmul         st,st(4)            ; y.y*x.y, y.x. y.y, x.x, x.y
  770.       fld          st(1)               ; y.x, y.y*x.y, y.x, y.y, x.x, x.y
  771.       fmul         st,st(4)            ; y.x*x.x,y.y*x.y,y.x y.y,x.x,x.y
  772.       fsubr                            ; newx=y.x*x.x-y.y*x.y,y.x,y.y,x.x,x.y
  773.       fxch         st(3)               ; x.x, y.x, y.y, newx, x.y
  774.       fmulp        st(2),st            ; y.x, y.y*x.x, newx, x.y
  775.       fmulp        st(3),st            ; y.y*x.x, newx, y.x*x.y
  776.       faddp        st(2),st            ; newx newy = y.x*x.y + x.x*y.y
  777.    END_INCL        Mul
  778. ; --------------------------------------------------------------------------
  779.    BEGN_OPER       LodMul              ; Load, Multiply
  780.    ; This is just load followed by multiply but it saves a fn. call
  781.    ;    and also allows optimizer enhancements.
  782.       FIXUP        LodMul, fld, Y      ; y.y x.x x.y
  783.       FIXUP        LodMul, fld, X      ; y.x y.y x.x x.y
  784.       fld          st(1)               ; y.y, y.x, y.y, x.x, x.y
  785.       fmul         st,st(4)            ; y.y*x.y, y.x. y.y, x.x, x.y
  786.       fld          st(1)               ; y.x, y.y*x.y, y.x, y.y, x.x, x.y
  787.       fmul         st, st(4)           ; y.x*x.x, y.y*x.y, y.x, y.y, x.x, x.y
  788.       fsubr                            ; newx=y.x*x.x-y.y*x.y,y.x,y.y,x.x,x.y
  789.       fxch         st(3)               ; x.x, y.x, y.y, newx, x.y
  790.       fmulp        st(2), st           ; y.x, y.y*x.x, newx, x.y
  791.       fmulp        st(3), st           ; y.y*x.x, newx, y.x*x.y
  792.       faddp        st(2), st           ; newx newy = y.x*x.y + x.x*y.y
  793.    END_OPER        LodMul
  794. ; --------------------------------------------------------------------------
  795.    BEGN_INCL       Div                 ; Divide
  796.    ; From FPU087.ASM with speedups
  797.       fld          st(1)               ; y.y,y.x,y.y,x.x,x.y
  798.       fmul         st,st               ; y.y*y.y,y.x,y.y,x.x,x.y
  799.       fld          st(1)               ; y.x,y.y*y.y,y.x,y.y,x.x,x.y
  800.       fmul         st,st               ; y.x*y.x,y.y*y.y,y.x,y.y,x.x,x.y
  801.       fadd                             ; mod,y.x,y.y,x.x,x.y
  802.       ftst
  803.       fstsw        ax
  804.       sahf
  805.       jz           short DivNotOk
  806.                                        ; can't do this divide until now
  807.       fdiv         st(1),st            ; mod,y.x=y.x/mod,y.y,x.x,x.y
  808.       fdivp        st(2),st            ; y.x,y.y=y.y/mod,x.x,x.y
  809.       fld          st(1)               ; y.y,y.x,y.y,x.x,x.y
  810.       fmul         st,st(4)            ; y.y*x.y,y.x,y.y,x.x,x.y
  811.       fld          st(1)               ; y.x,y.y*x.y,y.x,y.y,x.x,x.y
  812.       fmul         st,st(4)            ; y.x*x.x,y.y*x.y,y.x,y.y,x.x,x.y
  813.       fadd                             ; y.x*x.x+y.y*x.y,y.x,y.y,x.x,x.y
  814.       fxch         st(3)               ; x.x,y.x,y.y,newx,x.y
  815.       fmulp        st(2),st            ; y.x,y.y*x.x,newx,x.y
  816.       fmulp        st(3),st            ; x.x*y.y,newx,y.x*x.y
  817.       fsubp        st(2),st            ; newx,newy
  818.       EXIT_OPER    Div
  819. DivNotOk:
  820.       POP_STK      5                   ; clear 5 from stack (!)
  821.       fld          _infinity           ; return a very large number
  822.       fld          st(0)
  823.    END_INCL        Div
  824. ; --------------------------------------------------------------------------
  825.    BEGN_INCL       Recip               ; Reciprocal
  826.    ; From FPU087.ASM
  827.       fld          st(1)               ; y, x, y
  828.       fmul         st,st               ; y*y, x, y
  829.       fld          st(1)               ; x, y*y, x, y
  830.       fmul         st,st               ; x*x, y*y, x, y
  831.       fadd                             ; mod, x, y
  832.       ftst
  833.       fstsw        ax
  834.       sahf
  835.       jz           short RecipNotOk
  836.       fdiv         st(1),st            ; mod, newx=x/mod, y
  837.       fchs                             ; -mod newx y
  838.       fdivp        st(2),st            ; newx, newy=y/-mod
  839.       EXIT_OPER    Recip
  840. RecipNotOk:
  841.       POP_STK      3                   ; clear three from stack
  842.       fld          _infinity           ; return a very large number
  843.       fld          st(0)
  844.    END_INCL        Recip
  845. ; --------------------------------------------------------------------------
  846.    BEGN_OPER       StoSqr              ; Sto, Square, save magnitude
  847.       fld          st(0)               ; x x y
  848.       FIXUP        StoSqr, fst, X      ;   "   (store x)
  849.       fmul         st(1),st            ; x x*x y
  850.       fmul         st,st(2)            ; xy xx y
  851.       fadd         st,st(0)            ; 2xy xx y
  852.       fxch         st(2)               ; y xx 2xy
  853.       FIXUP        StoSqr, fst, Y      ;    "     (store y)
  854.       fmul         st,st(0)            ; yy xx 2xy
  855.    ; It is now safe to overlay si here
  856.       mov          si, WORD PTR _v     ; si -> variables
  857.       fld          st(1)               ; xx yy xx 2xy
  858.       fadd         st,st(1)            ; xx+yy yy xx 2xy
  859.       fstp         QWORD PTR [si+LASTSQR] ; yy xx 2xy
  860.       fsubp        st(1),st            ; xx-yy 2xy
  861.    END_OPER        StoSqr
  862. ; --------------------------------------------------------------------------
  863.    BEGN_OPER       StoSqr0             ; Sto, Square, don't save magnitude
  864.       fld          st(0)               ; x x y
  865.       FIXUP        StoSqr0, fst, X     ; store x
  866.       fld          st(0)               ; x x x y
  867.       fmul         st,st(3)            ; xy x x y
  868.       fadd         st,st               ; 2xy x x y
  869.       fxch         st(3)               ; y x x 2xy
  870.       FIXUP        StoSqr0, fst, Y     ; store y
  871.       fadd         st(2),st            ; y x x+y 2xy
  872.       fsubp        st(1),st            ; x-y x+y 2xy
  873.       fmulp        st(1),st            ; xx-yy 2xy
  874.    END_OPER        StoSqr0
  875. ; --------------------------------------------------------------------------
  876.    BEGN_INCL       Mod2                ; Modulus (uses a reg)
  877.       fmul         st,st               ; xx y
  878.       fldz                             ; 0 xx y
  879.       fxch         st(2)               ; y xx 0
  880.       fmul         st,st               ; yy xx 0
  881.       fadd                             ; mod 0
  882.    END_INCL        Mod2
  883. ; --------------------------------------------------------------------------
  884.    BEGN_OPER       LodMod2             ; Load, Modulus (uses a reg)
  885.       fldz                             ; 0 ...
  886.       FIXUP        LodMod2, fld, X     ; x 0 ...
  887.       fmul         st,st               ; xx 0
  888.       FIXUP        LodMod2, fld, Y     ; y xx 0
  889.       fmul         st,st               ; yy xx 0
  890.       fadd                             ; mod 0
  891.    END_OPER        LodMod2
  892. ; --------------------------------------------------------------------------
  893.    BEGN_OPER       StoMod2             ; Store, Modulus (uses a reg)
  894.       FIXUP        StoMod2, fst, X     ; x y
  895.       fmul         st,st               ; xx y
  896.       fldz                             ; 0 xx y
  897.       fxch         st(2)               ; y xx 0
  898.       FIXUP        StoMod2, fst, Y     ; y xx 0
  899.       fmul         st,st               ; yy xx 0
  900.       fadd                             ; mod 0
  901.    END_OPER        StoMod2
  902. ; --------------------------------------------------------------------------
  903.    BEGN_OPER       Clr2                ; Test ST, clear FPU
  904.       ftst
  905.       fstsw        ax
  906.       fninit                           ; fstsw will complete first
  907.       and          ah,01000000b        ; return 1 if zf=1
  908.       shr          ax,14               ; AX will be returned by fFormula()
  909.    END_OPER        Clr2
  910. ; --------------------------------------------------------------------------
  911.    BEGN_OPER       PLodAdd             ; Load, Add (uses no regs)
  912.       fxch                             ; y x
  913.       FIXUP        PLodAdd, fadd, Y    ; add y from memory
  914.       fxch                             ; x y
  915.       FIXUP        PLodAdd, fadd, X    ; add x, overlap execution
  916.    END_OPER        PLodAdd
  917. ; --------------------------------------------------------------------------
  918.    BEGN_OPER       PLodSub             ; Load, Subtract (uses no regs)
  919.       fxch
  920.       FIXUP        PLodSub, fsub, Y    ; sub y from memory
  921.       fxch                             ; x y
  922.       FIXUP        PLodSub, fsub, X    ; sub x, overlap execution
  923.    END_OPER        PLodSub
  924. ; --------------------------------------------------------------------------
  925.    BEGN_OPER       LodDup              ; Load, duplicate
  926.       FIXUP        LodDup, fld, Y      ; y ...
  927.       FIXUP        LodDup, fld, X      ; x y ...
  928.       fld          st(1)               ; y x y ...
  929.       fld          st(1)               ; x y x y ...
  930.    END_OPER        LodDup
  931. ; --------------------------------------------------------------------------
  932.    BEGN_OPER       LodSqr              ; Load, square (no save lastsqr)
  933.       FIXUP        LodSqr, fld, Y      ; y ...
  934.       fld          st(0)               ; y y ...
  935.       fadd         st(1),st            ; y 2y ...
  936.       fld          st(0)               ; y y 2y
  937.       FIXUP        LodSqr, fld, X      ; x y y 2y ...
  938.       fmul         st(3),st            ; x y y 2xy ...
  939.       fadd         st(2),st            ; x y X+y 2xy ...
  940.       fsubrp       st(1),st            ; x-y x+y 2xy ...
  941.       fmul                             ; xx-yy 2xy ...
  942.    END_OPER        LodSqr
  943. ; --------------------------------------------------------------------------
  944.    BEGN_OPER       LodSqr2             ; Load, square (save lastsqr)
  945.       FIXUP        LodSqr2, fld, Y     ; y ...
  946.       fld          st(0)               ; y y ...
  947.       fadd         st(1),st            ; y 2y ...
  948.       fmul         st,st(0)            ; yy 2y ...
  949.       FIXUP        LodSqr2, fld, X     ; x yy 2y ...
  950.       fmul         st(2),st            ; x yy 2xy ...
  951.       mov          si,WORD PTR _v      ; put address of v in si
  952.       fmul         st,st(0)            ; xx yy 2xy ...
  953.       fld          st(0)               ; xx xx yy 2xy
  954.       fadd         st,st(2)            ; mod xx yy 2xy
  955.       fstp         QWORD PTR [si+LASTSQR] ; xx yy 2xy ... (save lastsqr)
  956.       fsubrp       st(1),st            ; xx-yy 2xy ...
  957.    END_OPER        LodSqr2
  958. ; --------------------------------------------------------------------------
  959.    BEGN_OPER       LodDbl              ; Load, double
  960.       FIXUP        LodDbl, fld, Y      ; load y
  961.       fadd         st,st(0)            ; double it
  962.       FIXUP        LodDbl, fld, X      ; same for x
  963.       fadd         st,st(0)
  964.    END_OPER        LodDbl
  965. ; --------------------------------------------------------------------------
  966.    BEGN_INCL       Dbl                 ; Double                  CAE 31OCT93
  967.       fxch                             ; y x ...
  968.       fadd         st,st(0)            ; 2y x ...
  969.       fxch                             ; x 2y ...
  970.       fadd         st,st(0)            ; 2x 2y ...
  971.    END_INCL        Dbl
  972. ; --------------------------------------------------------------------------
  973.    BEGN_INCL       Mod                 ; Modulus (uses no regs)
  974.       fmul         st,st               ; x*x y
  975.       fxch                             ; y x*x
  976.       fmul         st,st               ; y*y x*x
  977.       fadd                             ; mod
  978.       fldz                             ; 0 mod
  979.       fxch                             ; mod 0
  980.    END_INCL        Mod
  981. ; --------------------------------------------------------------------------
  982. ; The following code was 'discovered' by experimentation.  The Intel manuals
  983. ;   really don't help much in writing this kind of code.
  984. ; --------------------------------------------------------------------------
  985.    BEGN_INCL       Push2               ; Push stack down from 8 to 6
  986.       fdecstp                          ; roll the stack
  987.       fdecstp                          ; ...
  988.       fstp         tbyte PTR es:[di]   ; store x on overflow stack
  989.       fstp         tbyte PTR es:[di+10] ; and y (ten bytes each)
  990.       add          di,20               ; adjust di
  991.    END_INCL        Push2
  992. ; --------------------------------------------------------------------------
  993.    BEGN_INCL       Pull2               ; Pull stack up from 2 to 4
  994.       fld          tbyte PTR es:[di-10] ; oldy x y
  995.       sub          di,20               ; adjust di now
  996.       fxch         st(2)               ; y x oldy
  997.       fld          tbyte PTR es:[di]   ; oldx y x oldy
  998.       fxch         st(2)               ; x y oldx oldy
  999.    END_INCL        Pull2
  1000. ; --------------------------------------------------------------------------
  1001.    BEGN_INCL       Push4               ; Push stack down from 8 to 4
  1002.       fdecstp                          ; roll the stack four times
  1003.       fdecstp
  1004.       fdecstp
  1005.       fdecstp
  1006.       fstp         tbyte PTR es:[di+20] ; save the bottom four numbers
  1007.       fstp         tbyte PTR es:[di+30] ; save full precision on overflow
  1008.       fstp         tbyte PTR es:[di]
  1009.       fstp         tbyte PTR es:[di+10]
  1010.       add          di,40                ; adjust di
  1011.    END_INCL        Push4
  1012. ; --------------------------------------------------------------------------
  1013.    BEGN_INCL       Push2a              ; Push stack down from 6 to 4
  1014.       fdecstp                          ; roll the stack 4 times
  1015.       fdecstp
  1016.       fdecstp
  1017.       fdecstp
  1018.       fstp         tbyte PTR es:[di]   ; save only two numbers
  1019.       fstp         tbyte PTR es:[di+10]
  1020.       add          di, 20
  1021.       fincstp                          ; roll back 2 times
  1022.       fincstp
  1023.    END_INCL        Push2a
  1024. ; --------------------------------------------------------------------------
  1025. ; End of stack overflow/underflow code.
  1026. ; --------------------------------------------------------------------------
  1027.    BEGN_INCL       Exp                ; Exponent
  1028.    ; From FPU387.ASM with mods to use less registers.
  1029.    ; Modified to preserve 80-bit accuracy.                      CAE 10NOV93
  1030.       fldln2                           ; ln2 x y
  1031.       fdivp        st(1),st            ; x/ln2 y
  1032.       fstp         TBYTE PTR es:[di]   ; y
  1033.       fsincos                          ; cosy, siny
  1034.       fld1                             ; 1 cos sin
  1035.       fld          TBYTE PTR es:[di]   ; x/ln2 1 cos sin
  1036.       fprem                            ; prem, 1, cos, sin
  1037.       f2xm1                            ; e**prem-1, 1, cos, sin
  1038.       fadd                             ; e**prem, cos, sin
  1039.       fld          TBYTE PTR es:[di]   ; x.x/ln2, e**prem, cos, sin
  1040.       fxch                             ; e**prem, x.x/ln2, cos, sin
  1041.       fscale                           ; e**x.x, x.x/ln2, cos, sin
  1042.       fstp         st(1)               ; e**x.x, cos, sin
  1043.       fmul         st(2),st            ; e**x.x, cos, z.y
  1044.       fmul                             ; z.x, z.y
  1045.    END_INCL        Exp
  1046. ; --------------------------------------------------------------------------
  1047.    BEGN_OPER       Pwr                 ; Power
  1048.    ; First exchange the top two complex numbers.
  1049.       fxch         st(2)               ; x.x y.y y.x x.y
  1050.       fxch                             ; y.y x.x y.x x.y
  1051.       fxch         st(3)               ; x.y x.x y.x y.y
  1052.       fxch                             ; x.x x.y y.x y.y
  1053.    ; Now take the log of the # on st.
  1054.       INCL_OPER    Pwr, Log            ; l.x l.y y.x y.y
  1055.       cmp          ax,1                ; log domain error?
  1056.       jne          domainok            ; nope
  1057.       cmp          _debugflag, 94      ; user wants old pwr?
  1058.       je           domainok            ; yup
  1059.       POP_STK      2                   ; clear two numbers
  1060.       fldz
  1061.       fldz
  1062.       EXIT_OPER    Pwr                 ; return (0,0)
  1063.    PARSALIGN
  1064. domainok:
  1065.    ; Inline multiply function from FPU087.ASM instead of include.
  1066.       fld          st(1)               ; y.y y.x y.y x.x x.y
  1067.       fmul         st,st(4)            ; y.y*x.y y.x y.y x.x x.y
  1068.       fld          st(1)               ; y.x y.y*x.y y.x y.y x.x x.y
  1069.       fmul         st,st(4)            ; y.x*x.x y.y*x.y y.x y.y x.x x.y
  1070.       fsubr                            ; newx=y.x*x.x-y.y*x.y y.x y.y x.x x.y
  1071.       fxch         st(3)               ; x.x y.x y.y newx x.y
  1072.       fmulp        st(2),st            ; y.x y.y*x.x newx x.y
  1073.       fmulp        st(3),st            ; y.y*x.x newx y.x*x.y
  1074.       faddp        st(2),st            ; newx newy=y.x*x.y+x.x*y.y
  1075.    ; Exp function from FPU387.ASM.  4 regs are free here.
  1076.    ; Modified to use the regs instead of memory.                 CAE 06NOV93
  1077.       fldln2                           ; ln2 x y
  1078.       fdiv                             ; x/ln2 y
  1079.       fxch                             ; y x/ln2
  1080.       fsincos                          ; cosy, siny, x/ln2
  1081.       fxch                             ; sin, cos, x/ln2
  1082.       fxch         st(2)               ; x/ln2, cos, sin
  1083.       fld1                             ; 1, x/ln2, cos, sin
  1084.       fld          st(1)               ; x/ln2, 1, x/ln2, cos, sin
  1085.       fprem                            ; prem, 1, x/ln2, cos, sin
  1086.       f2xm1                            ; e**prem-1, 1, x/ln2, cos, sin
  1087.       fadd                             ; e**prem, x/ln2, cos, sin
  1088.       fscale                           ; e**x.x, x.x/ln2, cos, sin
  1089.       fstp         st(1)               ; e**x.x, cos, sin
  1090.       fmul         st(2),st            ; e**x.x, cos, z.y
  1091.       fmul                             ; z.x, z.y
  1092.    END_OPER        Pwr
  1093. ; --------------------------------------------------------------------------
  1094.    BEGN_OPER       LodRealPwr          ; lod, real, power         CAE 6NOV93
  1095.    ; First take the log of the # on st.
  1096.       INCL_OPER    LodRealPwr, Log     ; l.x l.y
  1097.    ; Inline multiply by a real.
  1098.       FIXUP        LodRealPwr, fld, X  ; y.x, x.x, x.y
  1099.       fmul         st(2),st            ; y.x, x.x, z.y
  1100.       fmulp        st(1),st            ; z.x z.y
  1101.    ; Exp function from FPU387.ASM.  4 regs are free here, so use them.
  1102.       fldln2                           ; ln2 x y
  1103.       fdiv                             ; x/ln2 y
  1104.       fxch                             ; y x/ln2
  1105.       fsincos                          ; cosy, siny, x/ln2
  1106.       fxch                             ; sin, cos, x/ln2
  1107.       fxch         st(2)               ; x/ln2, cos, sin
  1108.       fld1                             ; 1, x/ln2, cos, sin
  1109.       fld          st(1)               ; x/ln2, 1, x/ln2, cos, sin
  1110.       fprem                            ; prem, 1, x/ln2, cos, sin
  1111.       f2xm1                            ; e**prem-1, 1, x/ln2, cos, sin
  1112.       fadd                             ; e**prem, x/ln2, cos, sin
  1113.       fscale                           ; e**x.x, x.x/ln2, cos, sin
  1114.       fstp         st(1)               ; e**x.x, cos, sin
  1115.       fmul         st(2),st            ; e**x.x, cos, z.y
  1116.       fmul                             ; z.x, z.y
  1117.    END_OPER        LodRealPwr
  1118. ; --------------------------------------------------------------------------
  1119.    BEGN_OPER       Cosh                ; Cosh
  1120.       INCL_OPER    Cosh, SinhCosh      ; sinhx coshx y
  1121.       fxch         st(2)               ; y coshx sinhx
  1122.       fsincos                          ; cosy siny coshx sinhx
  1123.       fmulp        st(2),st            ; siny x=cosy*coshx sinhx
  1124.       fmulp        st(2),st            ; x y=sinhx*siny
  1125.    END_OPER        Cosh
  1126. ; --------------------------------------------------------------------------
  1127.    BEGN_OPER       Sinh                ; Sinh
  1128.       INCL_OPER    Sinh, SinhCosh      ; sinhx coshx y
  1129.       fxch         st(2)               ; y coshx sinhx
  1130.       fsincos                          ; cosy siny coshx sinhx
  1131.       fmulp        st(3),st            ; siny coshx x=sinhx*cosy
  1132.       fmulp        st(1),st            ; y=coshx*siny x
  1133.       fxch                             ; x y
  1134.    END_OPER        Sinh
  1135. ; --------------------------------------------------------------------------
  1136.    BEGN_OPER       Sin                 ; Sin
  1137.       fsincos                          ; cosx sinx y
  1138.       fxch         st(2)               ; y sinx cosx
  1139.       INCL_OPER    Sin, SinhCosh       ; sinhy coshy sinx cosx
  1140.       fmulp        st(3),st            ; coshy sinx y=cosx*sinhy
  1141.       fmulp        st(1),st            ; x=sinx*coshy y
  1142.    END_OPER        Sin
  1143. ; --------------------------------------------------------------------------
  1144.    BEGN_OPER       Cos                 ; Cos
  1145.       fsincos                          ; cosx sinx y
  1146.       fxch         st(2)               ; y sinx cosx
  1147.       INCL_OPER    Cos, SinhCosh       ; sinhy coshy sinx cosx
  1148.       fchs                             ; -sinhy coshy sinx cosx
  1149.       fmulp        st(2),st            ; coshy y=-sinhy*sinx cosx
  1150.       fmulp        st(2),st            ; y x=cosx*coshy
  1151.       fxch                             ; x y
  1152.    END_OPER        Cos
  1153. ; --------------------------------------------------------------------------
  1154.    BEGN_OPER       CosXX               ; CosXX
  1155.       fsincos                          ; cosx sinx y
  1156.       fxch         st(2)               ; y sinx cosx
  1157.       INCL_OPER    CosXX, SinhCosh     ; sinhy coshy sinx cosx
  1158.       ; note missing fchs here
  1159.       fmulp        st(2),st            ; coshy y=sinhy*sinx cosx
  1160.       fmulp        st(2),st            ; y x=cosx*coshy
  1161.       fxch                             ; x y
  1162.    END_OPER        CosXX
  1163. ; --------------------------------------------------------------------------
  1164.    BEGN_OPER       Tan                 ; Tan
  1165.       fadd         st,st               ; 2x y
  1166.       fsincos                          ; cos2x sin2x y
  1167.       fxch         st(2)               ; y sin2x cos2x
  1168.       fadd         st,st               ; 2y sin2x cos2x
  1169.       INCL_OPER    Tan, SinhCosh       ; sinh2y cosh2y sin2x cos2x
  1170.       fxch                             ; cosh2y sinh2y sin2x cos2x
  1171.       faddp        st(3),st            ; sinhy sinx denom=cos2x+cosh2y
  1172.       fld          st(2)               ; denom sinh2y sin2x denom
  1173.       fdivp        st(2),st            ; sinh2y x=sin2x/denom denom
  1174.       fdivrp       st(2),st            ; x y=sinh2y/denom
  1175.    END_OPER        Tan
  1176. ; --------------------------------------------------------------------------
  1177.    BEGN_OPER       CoTan               ; CoTan
  1178.       fadd         st,st               ; 2x y
  1179.       fsincos                          ; cos2x sin2x y
  1180.       fxch         st(2)               ; y sin2x cos2x
  1181.       fadd         st,st               ; 2y sin2x cos2x
  1182.       INCL_OPER    CoTan, SinhCosh     ; sinh2y cosh2y sin2x cos2x
  1183.       fxch                             ; cosh2y sinh2y sin2x cos2x
  1184.       fsubrp       st(3),st            ; sinh2y sin2x denom=cosh2y-cos2x
  1185.       fld          st(2)               ; denom sinh2y sin2x denom
  1186.       fdivp        st(2),st            ; sinh2y x=sin2x/denom denom
  1187.       fchs                             ; -sinh2y x denom
  1188.       fdivrp       st(2),st            ; x y=-sinh2y/denom
  1189.    END_OPER        CoTan
  1190. ; --------------------------------------------------------------------------
  1191.    BEGN_OPER       Tanh                ; Tanh
  1192.       fadd         st,st               ; 2x y
  1193.       INCL_OPER    Tanh, SinhCosh      ; sinh2x cosh2x y
  1194.       fxch         st(2)               ; y cosh2x sinh2x
  1195.       fadd         st,st               ; 2y cosh2x sinh2x
  1196.       fsincos                          ; cos2y sin2y cosh2x sinh2x
  1197.       faddp        st(2),st            ; sin2y denom=cos2y+cosh2x sinh2x
  1198.       fxch                             ; denom sin2y sinh2x
  1199.       fdiv         st(1),st            ; denom y=sin2y/denom sinh2x
  1200.       fdivp        st(2),st            ; y x=sinh2x/denom
  1201.       fxch                             ; x y
  1202.    END_OPER        Tanh
  1203. ; --------------------------------------------------------------------------
  1204.    BEGN_OPER       CoTanh              ; CoTanh
  1205.       fadd         st,st               ; 2x y
  1206.       INCL_OPER    CoTanh, SinhCosh    ; sinh2x cosh2x y
  1207.       fxch         st(2)               ; y cosh2x sinh2x
  1208.       fadd         st,st               ; 2y cosh2x sinh2x
  1209.       fsincos                          ; cos2y sin2y cosh2x sinh2x
  1210.       fsubp        st(2),st            ; sin2y denom=cosh2x-cos2y sinh2x
  1211.       fchs                             ; -sin2y denom sinh2x
  1212.       fxch                             ; denom -sin2y sinh2x
  1213.       fdiv         st(1),st            ; denom y=-sin2y/denom sinh2x
  1214.       fdivp        st(2),st            ; y x=sinh2x/denom
  1215.       fxch                             ; x y
  1216.    END_OPER CoTanh
  1217. ; --------------------------------------------------------------------------
  1218. ; JCO added Sqrt .. CAbs for version 19.
  1219. ; CAE updated them 15Feb94 to work with compiler mode.
  1220. ; --------------------------------------------------------------------------
  1221.    BEGN_OPER       Sqrt                ; Sqrt
  1222.       GEN_SQRT
  1223.    END_OPER Sqrt
  1224. ; --------------------------------------------------------------------------
  1225.    BEGN_OPER       ASin                ; ArcSin
  1226.       fld          st(1)               ; y x y
  1227.       fld          st(1)               ; x y x y
  1228.       GEN_SQR0                         ; tz1.x tz1.y x y
  1229.       fxch         st(1)               ; tz1.y tz1.x x y
  1230.       fchs                             ; -tz1.y tz1.x x y
  1231.       fxch         st(1)               ; tz1.x -tz1.y x y
  1232.       fsubr        __1_                ; 1-tz1.x -tz1.y x y
  1233.       GEN_SQRT                         ; tz1.x tz1.y x y
  1234.       fsubrp       st(3),st            ; tz1.y x tz1.x-y
  1235.       fadd                             ; tz1.y+x tz1.x-y
  1236.       fxch         st(1)               ; tz1.x-y tz1.y+x
  1237.       INCL_OPER    ASin, Log           ; l.x l.y
  1238.       fchs                             ; -l.x l.y
  1239.       fxch         st(1)               ; l.y -l.x ;; rz = (-i)*l
  1240.    END_OPER ASin
  1241. ; --------------------------------------------------------------------------
  1242.    BEGN_OPER       ACos                ; ArcCos
  1243.       fld          st(1)               ; y x y
  1244.       fld          st(1)               ; x y x y
  1245.       GEN_SQR0                         ; tz1.x tz1.y x y
  1246.       fsub         __1_                ; tz1.x-1 tz1.y x y
  1247.       GEN_SQRT                         ; tz.x tz.y x y
  1248.       faddp        st(2),st            ; tz.y tz.x+x y
  1249.       faddp        st(2),st            ; tz.x+x tz.y+y
  1250.       INCL_OPER    ACos, Log           ; l.x l.y
  1251.       fchs                             ; -l.x l.y
  1252.       fxch         st(1)               ; l.y -l.x ;; rz = (-i)*l
  1253.    END_OPER ACos
  1254. ; --------------------------------------------------------------------------
  1255.    BEGN_OPER       ASinh               ; ArcSinh
  1256.       fld          st(1)               ; y x y
  1257.       fld          st(1)               ; x y x y
  1258.       GEN_SQR0                         ; tz1.x tz1.y x y
  1259.       fadd         __1_                ; tz1.x+1 tz1.y x y
  1260.       GEN_SQRT                         ; tz.x tz.y x y
  1261.       faddp        st(2),st            ; tz.y tz.x+x y
  1262.       faddp        st(2),st            ; tz.x+x tz.y+y
  1263.       INCL_OPER    ASinh, Log          ; l.x l.y
  1264.    END_OPER ASinh
  1265. ; --------------------------------------------------------------------------
  1266.    BEGN_OPER       ACosh               ; ArcCosh
  1267.       fld          st(1)               ; y x y
  1268.       fld          st(1)               ; x y x y
  1269.       GEN_SQR0                         ; tz1.x tz1.y x y
  1270.       fsub         __1_                ; tz1.x+1 tz1.y x y
  1271.       GEN_SQRT                         ; tz.x tz.y x y
  1272.       faddp        st(2),st            ; tz.y tz.x+x y
  1273.       faddp        st(2),st            ; tz.x+x tz.y+y
  1274.       INCL_OPER    ACosh, Log          ; l.x l.y
  1275.    END_OPER ACosh
  1276. ; --------------------------------------------------------------------------
  1277.    BEGN_OPER       ATanh               ; ArcTanh
  1278.       fld          st(1)               ; y x y
  1279.       fchs                             ; -y x y
  1280.       fld          st(1)               ; x -y x y
  1281.       fld1                             ; 1 x -y x y
  1282.       fadd         st(3),st            ; 1 x -y 1+x y
  1283.       fsubr                            ; 1-x -y 1+x y
  1284.       INCL_OPER    ATanh, Div          ; d.x d.y
  1285.    ; From FPU387.ASM
  1286.    ; Log is called by Pwr and is also called directly.
  1287.       ftst
  1288.       fstsw        ax
  1289.       sahf
  1290.       jnz          short ATanh_NotBothZero
  1291.       fxch                             ; y x
  1292.       ftst
  1293.       fstsw        ax
  1294.       sahf
  1295.       fxch                             ; x y
  1296.       jnz          short ATanh_NotBothZero
  1297.       POP_STK      2                   ; clear two numbers
  1298.       fldz
  1299.       fldz
  1300.       jmp          SHORT End_Log_ATanh ; return (0,0)
  1301.    PARSALIGN
  1302. ATanh_NotBothZero:
  1303.       fld          st(1)               ; y x y
  1304.       fld          st(1)               ; x y x y
  1305.       fpatan                           ; z.y x y
  1306.       fxch         st(2)               ; y x z.y
  1307.       fmul         st,st(0)            ; yy x z.y
  1308.       fxch                             ; x yy z.y
  1309.       fmul         st,st(0)            ; xx yy z.y
  1310.       fadd                             ; mod z.y
  1311.       fldln2                           ; ln2, mod, z.y
  1312.       fmul         _PointFive          ; ln2/2, mod, z.y
  1313.       fxch                             ; mod, ln2/2, z.y
  1314.       fyl2x                            ; z.x, z.y
  1315. End_Log_ATanh:
  1316.       fld          _PointFive          ; .5 l.x l.y
  1317.       fmul         st(1),st            ; .5 l.x/2 l.y
  1318.       fmulp        st(2),st            ; l.x/2 l.y/2
  1319.    END_OPER ATanh
  1320. ; --------------------------------------------------------------------------
  1321.    BEGN_OPER       ATan                ; ArcTan
  1322.       fxch                             ; y x
  1323.       fld          st(1)               ; x y x
  1324.       fchs                             ; -x y x
  1325.       fxch         st(2)               ; x y -x
  1326.       fld          st(1)               ; y x y -x
  1327.       fld1                             ; 1 y x y -x
  1328.       fadd         st(3),st            ; 1 y x 1+y -x
  1329.       fsubr                            ; 1-y x 1+y -x
  1330.       INCL_OPER    ATan, Div           ; d.x d.y
  1331.    ; CAE put log fn inline 15Feb95
  1332.       ftst
  1333.       fstsw        ax
  1334.       sahf
  1335.       jnz          short ATan_NotBothZero
  1336.       fxch                             ; y x
  1337.       ftst
  1338.       fstsw        ax
  1339.       sahf
  1340.       fxch                             ; x y
  1341.       jnz          short ATan_NotBothZero
  1342.       POP_STK      2                   ; clear two numbers
  1343.       fldz
  1344.       fldz
  1345.       jmp          short End_Log_ATan  ; return (0,0)
  1346.    PARSALIGN
  1347. ATan_NotBothZero:
  1348.       fld          st(1)               ; y x y
  1349.       fld          st(1)               ; x y x y
  1350.       fpatan                           ; z.y x y
  1351.       fxch         st(2)               ; y x z.y
  1352.       fmul         st,st(0)            ; yy x z.y
  1353.       fxch                             ; x yy z.y
  1354.       fmul         st,st(0)            ; xx yy z.y
  1355.       fadd                             ; mod z.y
  1356.       fldln2                           ; ln2, mod, z.y
  1357.       fmul         _PointFive          ; ln2/2, mod, z.y
  1358.       fxch                             ; mod, ln2/2, z.y
  1359.       fyl2x                            ; z.x, z.y
  1360. End_Log_ATan:
  1361.       fld          _PointFive          ; .5 l.x l.y
  1362.       fmul         st(1),st            ; .5 z.y=l.x/2 l.y
  1363.       fmulp        st(2),st            ; z.y l.y/2
  1364.       fxch                             ; l.y/2 z.y
  1365.       fchs                             ; z.x=-l.y/2 z.y
  1366.    END_OPER ATan
  1367. ; --------------------------------------------------------------------------
  1368.    BEGN_OPER       CAbs                ; Complex Absolute Value
  1369.       fmul         st,st               ; x*x y
  1370.       fxch                             ; y x*x
  1371.       fmul         st,st               ; y*y x*x
  1372.       fadd                             ; y*y+x*x
  1373.       fsqrt                            ; mag=sqrt(yy+xx)
  1374.       fldz                             ; 0 mag
  1375.       fxch                             ; mag 0
  1376.    END_OPER CAbs
  1377. ; --------------------------------------------------------------------------
  1378. ; End of new functions.                                          CAE 15Feb95
  1379. ; --------------------------------------------------------------------------
  1380.    BEGN_OPER       LT                  ; <
  1381.    ; Arg2->d.x = (double)(Arg2->d.x < Arg1->d.x);
  1382.       fcomp        st(2)               ; y.y, x.x, x.y, comp arg1 to arg2
  1383.       fstsw        ax
  1384.       POP_STK      3
  1385.       sahf
  1386.       fldz                             ; 0 (Arg2->d.y = 0.0;)
  1387.       jbe          short LTfalse       ; jump if arg1 <= arg2
  1388.       fld1                             ; 1 0 (return arg2 < arg1)
  1389.       EXIT_OPER    LT
  1390. LTfalse:
  1391.       fldz                             ; 0 0
  1392.    END_OPER        LT
  1393. ; --------------------------------------------------------------------------
  1394.    BEGN_INCL       LT2                 ; LT, set AX, clear FPU
  1395.    ; returns !(Arg2->d.x < Arg1->d.x) in ax
  1396.       fcom         st(2)               ; compare arg1, arg2
  1397.       fstsw        ax
  1398.       fninit
  1399.       sahf
  1400.       setbe        al                  ; return (Arg1 <= Arg2) in AX
  1401.       xor          ah,ah
  1402.    END_INCL        LT2
  1403. ; --------------------------------------------------------------------------
  1404.    BEGN_OPER       LodLT               ; load, LT
  1405.    ; return (1,0) on stack if arg2 < arg1
  1406.       FIXUP        LodLT, fcomp, X     ; compare arg2 to arg1, pop st
  1407.       fstsw        ax                  ; y ...
  1408.       POP_STK      1                   ; ...
  1409.       sahf
  1410.       fldz                             ; 0 ...
  1411.       jae          short LodLTfalse    ; jump when arg2 >= arg1
  1412.       fld1                             ; 1 0 ...
  1413.       EXIT_OPER    LodLT
  1414. LodLTfalse:
  1415.       fldz                             ; 0 0 ...
  1416.    END_OPER        LodLT
  1417. ; --------------------------------------------------------------------------
  1418.    BEGN_OPER       LodLT2              ; Lod, LT, set AX, clear FPU
  1419.    ; returns !(Arg2->d.x < Arg1->d.x) in ax
  1420.       FIXUP        LodLT2, fcom, X     ; compare arg2, arg1
  1421.       fstsw        ax
  1422.       fninit                           ; clear fpu
  1423.       sahf
  1424.       setae        al                  ; set al when arg2 >= arg1
  1425.       xor          ah,ah               ; clear ah
  1426.    END_OPER        LodLT2              ; ret 0 in ax for true, 1 for false
  1427. ; --------------------------------------------------------------------------
  1428.    BEGN_OPER       LodLTMul            ; Lod, LT, Multiply (needs 4 on stack)
  1429.    ; for '<expr> * ( <expr> < <var> )'
  1430.    ; return number on stack if arg2 < arg1
  1431.       FIXUP        LodLTMul, fcomp, X  ; comp Arg2 to Arg1, pop st
  1432.       fstsw        ax                  ; save status
  1433.       POP_STK      1                   ; clear 1 from stack
  1434.       sahf
  1435.       jae          short LodLTMulfalse ; jump if arg2 >= arg1
  1436.       EXIT_OPER    LodLTMul            ; return value on st
  1437.    PARSALIGN
  1438. LodLTMulfalse:
  1439.       POP_STK      2                   ; return (0,0)
  1440.       fldz
  1441.       fldz
  1442.    END_OPER        LodLTMul
  1443. ; --------------------------------------------------------------------------
  1444.    BEGN_INCL       GT                  ; >
  1445.    ; Arg2->d.x = (double)(Arg2->d.x > Arg1->d.x);
  1446.       fcomp        st(2)               ; compare arg1, arg2
  1447.       fstsw        ax
  1448.       POP_STK      3
  1449.       sahf
  1450.       fldz                             ; 0 (Arg2->d.y = 0.0;)
  1451.       jae          short GTfalse       ; jump if Arg1 >= Arg2
  1452.       fld1                             ; 1 0, return arg2 > arg1
  1453.       EXIT_OPER    GT
  1454. GTfalse:
  1455.       fldz                             ; 0 0
  1456.    END_INCL        GT
  1457. ; --------------------------------------------------------------------------
  1458.    BEGN_INCL       GT2                 ; GT, set AX, clear FPU
  1459.    ; returns !(Arg2->d.x > Arg1->d.x) in ax
  1460.       fcom         st(2)               ; compare arg1, arg2
  1461.       fstsw        ax
  1462.       fninit
  1463.       sahf
  1464.       setae        al                  ; return (Arg1 >= Arg2) in AX
  1465.       xor          ah,ah
  1466.    END_INCL        GT2
  1467. ; --------------------------------------------------------------------------
  1468.    BEGN_OPER       LodGT               ; load, GT
  1469.    ; return (1,0) on stack if arg2 > arg1
  1470.       FIXUP        LodGT, fcomp, X     ; compare arg2 to arg1, pop st
  1471.       fstsw        ax                  ; y ...
  1472.       POP_STK      1                   ; ...
  1473.       sahf
  1474.       fldz                             ; 0 ...
  1475.       jbe          short LodGTfalse    ; jump when arg2 <= arg1
  1476.       fld1                             ; 1 0 ...
  1477.       EXIT_OPER    LodGT
  1478. LodGTfalse:
  1479.       fldz                             ; 0 0 ...
  1480.    END_OPER        LodGT
  1481. ; --------------------------------------------------------------------------
  1482.    BEGN_OPER       LodGT2              ; Lod, GT, set AX, clear FPU
  1483.    ; returns !(Arg2->d.x > Arg1->d.x) in AX
  1484.       FIXUP        LodGT2, fcom, X     ; compare arg2, arg1
  1485.       fstsw        ax
  1486.       fninit                           ; clear fpu
  1487.       sahf
  1488.       setbe        al                  ; set al when arg2 <= arg1
  1489.       xor          ah,ah               ; clear ah
  1490.    END_OPER        LodGT2              ; ret 0 in ax for true, 1 for false
  1491. ; --------------------------------------------------------------------------
  1492.    BEGN_INCL       LTE                 ; <=
  1493.    ; Arg2->d.x = (double)(Arg2->d.x <= Arg1->d.x);
  1494.       fcomp        st(2)               ; y x y, comp Arg1 to Arg2
  1495.       fstsw        ax                  ; save status now
  1496.       POP_STK      3
  1497.       fldz                             ; 0 (Arg2->d.y = 0.0;)
  1498.       sahf
  1499.       jb           short LTEfalse      ; jump if arg1 > arg2
  1500.       fld1                             ; 1 0, ret arg2 <= arg1
  1501.       EXIT_OPER    LTE
  1502. LTEfalse:
  1503.       fldz                             ; 0 0
  1504.    END_INCL        LTE
  1505. ; --------------------------------------------------------------------------
  1506.    BEGN_INCL       LTE2                ; LTE, test ST, clear
  1507.    ; return !(Arg2->d.x <= Arg1->d.x) in AX
  1508.       fcom         st(2)               ; comp Arg1 to Arg2
  1509.       fstsw        ax
  1510.       fninit                           ; clear stack
  1511.       and          ah,1                ; mask cf
  1512.       shr          ax,8                ; ax=1 when arg1 < arg1
  1513.    END_INCL        LTE2                ; return (Arg1 < Arg2),
  1514. ; --------------------------------------------------------------------------
  1515.    BEGN_OPER       LodLTE              ; load, LTE
  1516.    ; return (1,0) on stack if arg2 <= arg1
  1517.       FIXUP        LodLTE, fcomp, X    ; compare arg2 to arg1, pop st
  1518.       fstsw        ax                  ; y ...
  1519.       POP_STK      1                   ; ...
  1520.       sahf
  1521.       fldz                             ; 0 ...
  1522.       ja           short LodLTEfalse   ; jump when arg2 > arg1
  1523.       fld1                             ; 1 0 ...
  1524.       EXIT_OPER    LodLTE
  1525. LodLTEfalse:
  1526.       fldz                             ; 0 0 ...
  1527.    END_OPER        LodLTE
  1528. ; --------------------------------------------------------------------------
  1529.    BEGN_OPER       LodLTE2             ; Load, LTE, test ST, clear
  1530.    ; return !(Arg2->d.x <= Arg1->d.x) in AX
  1531.       FIXUP        LodLTE2, fcom, X    ; comp Arg2 to Arg1
  1532.       fstsw        ax
  1533.       fninit
  1534.       sahf
  1535.       seta         al
  1536.       xor          ah,ah               ; ax=1 for expr. false
  1537.    END_OPER        LodLTE2             ; return (Arg2 > Arg1)
  1538. ; --------------------------------------------------------------------------
  1539.    BEGN_OPER       LodLTEMul           ; Lod, LTE, Multiply (needs 4 on stk)
  1540.    ; for '<expr> * ( <expr> <= <var> )'
  1541.    ; return number on stack if arg2 <= arg1
  1542.       FIXUP        LodLTEMul, fcomp, X ; comp Arg2 to Arg1, pop st
  1543.       fstsw        ax                  ; save status
  1544.       POP_STK      1                   ; clear 1 from stack
  1545.       sahf
  1546.       ja           short LodLTEMulfalse ; jump if arg2 > arg1
  1547.       EXIT_OPER    LodLTEMul           ; return value on st
  1548.    PARSALIGN
  1549. LodLTEMulfalse:
  1550.       POP_STK      2                   ; return (0,0)
  1551.       fldz
  1552.       fldz
  1553.    END_OPER        LodLTEMul
  1554. ; --------------------------------------------------------------------------
  1555.    BEGN_OPER       LodLTEAnd2          ; Load, LTE, AND, test ST, clear
  1556.    ; this is for 'expression && (expression <= value)'
  1557.    ; stack has {arg2.x arg2.y logical.x junk} on entry (arg1 in memory)
  1558.    ; Arg2->d.x = (double)(Arg2->d.x <= Arg1->d.x);
  1559.       FIXUP        LodLTEAnd2, fcom, X ; comp Arg2 to Arg1
  1560.       fstsw        ax
  1561.       sahf
  1562.       fxch         st(2)               ; logical.x arg2.y arg2.x junk ...
  1563.       ja           LTEA2RFalse         ; right side is false, Arg2 > Arg1
  1564.       ftst                             ; now see if left side of expr is true
  1565.       fstsw        ax
  1566.       sahf
  1567.       fninit                           ; clear fpu
  1568.       jz           LTEA2LFalse         ; jump if left side of && is false
  1569.       xor          ax,ax               ; return zero in ax for expr true
  1570.       ret                              ; changed EXIT_OPER->ret  CAE 30DEC93
  1571. LTEA2RFalse:
  1572.       fninit
  1573. LTEA2LFalse:
  1574.       mov          ax,1                ; return ax=1 for condition false
  1575.    END_OPER        LodLTEAnd2
  1576. ; --------------------------------------------------------------------------
  1577.    BEGN_INCL       GTE                 ; >=
  1578.    ; Arg2->d.x = (double)(Arg2->d.x >= Arg1->d.x);
  1579.       fcomp        st(2)               ; y x y (compare arg1,arg2)
  1580.       fstsw        ax
  1581.       POP_STK      3                   ; clear 3 from stk
  1582.       sahf
  1583.       fldz                             ; 0 (Arg2->d.y = 0.0;)
  1584.       ja           short GTEfalse      ; jmp if arg1 > arg2
  1585.       fld1                             ; 1 0 (return arg2 >= arg1 on stack)
  1586.       EXIT_OPER    GTE
  1587. GTEfalse:
  1588.       fldz                             ; 0 0
  1589.    END_INCL        GTE
  1590. ; --------------------------------------------------------------------------
  1591.    BEGN_OPER       LodGTE              ; load, GTE
  1592.    ; return (1,0) on stack if arg2 >= arg1
  1593.       FIXUP        LodGTE, fcomp, X    ; compare arg2 to arg1, pop st
  1594.       fstsw        ax                  ; y ...
  1595.       POP_STK      1                   ; ...
  1596.       fldz                             ; 0 ...
  1597.       sahf
  1598.       jb           short LodGTEfalse   ; jump when arg2 < arg1
  1599.       fld1                             ; 1 0 ...
  1600.       EXIT_OPER    LodGTE
  1601. LodGTEfalse:
  1602.       fldz                             ; 0 0 ...
  1603.    END_OPER        LodGTE
  1604. ; --------------------------------------------------------------------------
  1605.    BEGN_OPER       LodGTE2             ; Lod, GTE, set AX, clear FPU
  1606.    ; return !(Arg2->d.x >= Arg1->d.x) in AX
  1607.       FIXUP        LodGTE2, fcom, X    ; compare arg2, arg1
  1608.       fstsw        ax
  1609.       fninit                           ; clear fpu
  1610.       and          ah,1                ; mask cf
  1611.       shr          ax,8                ; shift it (AX = 1 when arg2 < arg1)
  1612.    END_OPER        LodGTE2             ; ret 0 in ax for true, 1 for false
  1613. ; --------------------------------------------------------------------------
  1614.    BEGN_INCL       EQ                  ; ==
  1615.    ; Arg2->d.x = (double)(Arg2->d.x == Arg1->d.x);
  1616.       fcomp        st(2)               ; compare arg1, arg2
  1617.       fstsw        ax
  1618.       POP_STK      3
  1619.       sahf
  1620.       fldz                             ; 0 (Arg2->d.y = 0.0;)
  1621.       jne          short EQfalse       ; jmp if arg1 != arg2
  1622.       fld1                             ; 1 0 (ret arg2 == arg1)
  1623.       EXIT_OPER    EQ
  1624. EQfalse:
  1625.       fldz
  1626.    END_INCL        EQ
  1627. ; --------------------------------------------------------------------------
  1628.    BEGN_OPER       LodEQ               ; load, EQ
  1629.    ; return (1,0) on stack if arg2 == arg1
  1630.       FIXUP        LodEQ, fcomp, X     ; compare arg2 to arg1, pop st
  1631.       fstsw        ax                  ; y ...
  1632.       POP_STK      1                   ; ...
  1633.       fldz                             ; 0 ...
  1634.       sahf
  1635.       jne          short LodEQfalse    ; jump when arg2 != arg1
  1636.       fld1                             ; 1 0 ... (return arg2 == arg1)
  1637.       EXIT_OPER    LodEQ
  1638. LodEQfalse:
  1639.       fldz                             ; 0 0 ...
  1640.    END_OPER        LodEQ
  1641. ; --------------------------------------------------------------------------
  1642.    BEGN_INCL       NE                  ; !=
  1643.    ; Arg2->d.x = (double)(Arg2->d.x != Arg1->d.x);
  1644.       fcomp        st(2)               ; compare arg1,arg2
  1645.       fstsw        ax
  1646.       POP_STK      3
  1647.       sahf
  1648.       fldz
  1649.       je           short NEfalse       ; jmp if arg1 == arg2
  1650.       fld1                             ; ret arg2 != arg1
  1651.       EXIT_OPER    NE
  1652. NEfalse:
  1653.       fldz
  1654.    END_INCL        NE
  1655. ; --------------------------------------------------------------------------
  1656.    BEGN_OPER       LodNE               ; load, NE
  1657.    ; return (1,0) on stack if arg2 != arg1
  1658.       FIXUP        LodNE, fcomp, X     ; compare arg2 to arg1, pop st
  1659.       fstsw        ax                  ; y ...
  1660.       POP_STK      1                   ; ...
  1661.       fldz                             ; 0 ...
  1662.       sahf
  1663.       je           short LodNEfalse    ; jump when arg2 == arg1
  1664.    ; CAE changed above 'jne' to 'je'                              9 MAR 1993
  1665.       fld1                             ; 1 0 ...
  1666.       EXIT_OPER    LodNE
  1667. LodNEfalse:
  1668.       fldz                             ; 0 0 ...
  1669.    END_OPER        LodNE
  1670. ; --------------------------------------------------------------------------
  1671.    BEGN_INCL       OR                  ; Or
  1672.    ; Arg2->d.x = (double)(Arg2->d.x || Arg1->d.x);
  1673.       ftst                             ; a1.x a1.y a2.x a2.y ...
  1674.       fstsw        ax
  1675.       sahf
  1676.       POP_STK      2                   ; a2.x a2.y ...
  1677.       jnz          short Arg1True
  1678.       ftst
  1679.       fstsw        ax
  1680.       sahf
  1681.       POP_STK      2                   ; ...
  1682.       fldz                             ; 0 ...
  1683.       jz           short NoneTrue
  1684.       fld1                             ; 1 0 ...
  1685.       EXIT_OPER    OR
  1686.    PARSALIGN
  1687. Arg1True:
  1688.       POP_STK      2                   ; ...
  1689.       fldz                             ; 0 ...
  1690.       fld1                             ; 1 0 ...
  1691.       EXIT_OPER    OR
  1692. NoneTrue:                              ; 0 ...
  1693.       fldz                             ; 0 0 ...
  1694.    END_INCL        OR
  1695. ; --------------------------------------------------------------------------
  1696.    BEGN_INCL       AND                 ; And
  1697.    ; Arg2->d.x = (double)(Arg2->d.x && Arg1->d.x);
  1698.       ftst                             ; a1.x a1.y a2.x a2.y ...
  1699.       fstsw        ax
  1700.       sahf
  1701.       POP_STK      2                   ; a2.x a2.y ...
  1702.       jz           short Arg1False
  1703.       ftst
  1704.       fstsw        ax
  1705.       sahf
  1706.       POP_STK      2                   ; ...
  1707.       fldz                             ; 0 ...
  1708.       jz           short Arg2False
  1709.       fld1                             ; 1 0 ...
  1710.       EXIT_OPER    AND
  1711.    PARSALIGN
  1712. Arg1False:
  1713.       POP_STK      2                   ; ...
  1714.       fldz                             ; 0 ...
  1715. Arg2False:
  1716.       fldz                             ; 0 0 ...
  1717.    END_INCL        AND
  1718. ; --------------------------------------------------------------------------
  1719.    BEGN_INCL       ANDClr2             ; And, test ST, clear FPU
  1720.    ; for bailouts using <condition> && <condition>
  1721.    ;  Arg2->d.x = (double)(Arg2->d.x && Arg1->d.x);
  1722.    ;  Returns !(Arg1 && Arg2) in ax
  1723.       ftst                             ; y.x y.y x.x x.y
  1724.       fstsw        ax
  1725.       sahf
  1726.       jz           short Arg1False2
  1727.       fxch         st(2)               ; x.x y.y y.x x.y
  1728.       ftst
  1729.       fstsw        ax
  1730.       sahf
  1731.       fninit
  1732.       jz           short Arg2False2
  1733. BothTrue2:
  1734.       xor          ax,ax
  1735.       ret                              ; changed EXIT_OPER->ret  CAE 30DEC93
  1736. Arg1False2:
  1737.       fninit
  1738. Arg2False2:
  1739.       mov          ax,1
  1740.    END_INCL        ANDClr2
  1741. ; --------------------------------------------------------------------------
  1742.    BEGN_INCL       ORClr2           ; Or, test ST, clear FPU      CAE 6NOV93
  1743.    ; for bailouts using <condition> || <condition>
  1744.    ;  Arg2->d.x = (double)(Arg2->d.x || Arg1->d.x);
  1745.    ;  Returns !(Arg1 || Arg2) in ax
  1746.       ftst                             ; y.x y.y x.x x.y
  1747.       fstsw        ax
  1748.       sahf
  1749.       jnz          short ORArg1True
  1750.       fxch         st(2)               ; x.x y.y y.x x.y
  1751.       ftst
  1752.       fstsw        ax
  1753.       sahf
  1754.       fninit
  1755.       jnz          short ORArg2True
  1756. ORNeitherTrue:
  1757.       mov          ax,1
  1758.       ret                              ; changed EXIT_OPER->ret  CAE 30DEC93
  1759. ORArg1True:
  1760.       fninit
  1761. ORArg2True:
  1762.       xor          ax,ax
  1763.    END_INCL        ORClr2
  1764.  
  1765. ; --------------------------------------------------------------------------
  1766.    assume          ds:DGROUP, es:nothing
  1767. ; --------------------------------------------------------------------------
  1768.  
  1769.    ifndef          COMPILER
  1770.  
  1771. ; --------------------------------------------------------------------------
  1772. ; called once per image
  1773. ; --------------------------------------------------------------------------
  1774.    public          _Img_Setup
  1775.    align           2
  1776.    ; Changed to FAR, FRAME/UNFRAME added by CAE 09OCT93
  1777. _Img_Setup         proc far
  1778.       FRAME        <si,di>
  1779.       les          si,_pfls            ; es:si = &pfls[0]
  1780.  
  1781.       mov          di,_LastOp          ; load index of lastop
  1782.  
  1783.       dec          di                  ; flastop now points at last operator
  1784.       ; above added by CAE 09OCT93 because of loop logic changes
  1785.  
  1786.       shl          di,2                ; convert to offset
  1787.       mov          bx,offset DGROUP:_fLastOp ; set bx for store
  1788.       add          di,si               ; di = offset lastop
  1789.       mov          WORD PTR [bx],di    ; save value of flastop
  1790.       mov          ax,es               ; es has segment value
  1791.       mov          WORD PTR [bx+2],ax  ; save seg for easy reload
  1792.       mov          ax,word ptr _v      ; build a ptr to Z
  1793.       add          ax,3*CARG+CPFX
  1794.       mov          _PtrToZ,ax          ; and save it
  1795.       UNFRAME      <di,si>
  1796.       ret
  1797. _Img_Setup         endp
  1798. ; --------------------------------------------------------------------------
  1799. ;  Hybrid orbitcalc/per-pixel routine (tested, but not implemented.)
  1800. ;
  1801. ;  To implement, stick the following code in calcfrac.c around line 788,
  1802. ;     just before the line that says "while (++coloriter < maxit)".
  1803. ; --------------------------------------------------------------------------
  1804. ;  if (curfractalspecific->orbitcalc == fFormula  /* 387 parser  */
  1805. ;        && periodicitycheck == 0
  1806. ;        && !show_orbit
  1807. ;        && inside >= -5
  1808. ;        && attractors == 0
  1809. ;        && !distest ){
  1810. ;     fFormulaX();  /* orbit till done  */
  1811. ;  } else
  1812. ; --------------------------------------------------------------------------
  1813.    public          _fFormulaX          ;                         CAE 09OCT93
  1814.    align           16
  1815. _fFormulaX         proc far
  1816.       push         si
  1817.       push         di
  1818.       mov          edx,_maxit          ; edx holds coloriter during loop
  1819.       mov          _coloriter,edx      ; set coloriter to maxit
  1820.       mov          ax,ds               ; save ds in ax
  1821.       lds          cx,_fLastOp         ; ds:cx -> one past last token
  1822.       mov          es,ax               ; es -> DGROUP
  1823.    assume          es:DGROUP, ds:nothing ; swap es, ds before any fn. calls
  1824.       jmp          short skipfirst     ; skip bailout test first time
  1825.    align           16
  1826. outer_loop:
  1827.       or           ax,ax               ; did bailout occur?
  1828.       jnz          short doneloop      ; yes, exit
  1829. skipfirst:
  1830.       dec          edx                 ; ++coloriter
  1831.       jle          short doneloop      ; yes, exit because of maxiter
  1832.       mov          bx,_InitOpPtr       ; bx -> one before first token
  1833.       mov          di,offset DGROUP:_s ; reset stk overflow ptr
  1834.    align           16
  1835. inner_loop2:
  1836.       cmp          bx,cx               ; time to quit yet?
  1837.       jae          short outer_loop    ; yes, bx points to last function
  1838.       add          bx,4                ; point to next pointer pair
  1839.       push         offset PARSERA_TEXT:inner_loop2 ; do this first
  1840.       mov          si,WORD PTR [bx+2]  ; set si to operand pointer
  1841.       jmp          WORD PTR [bx]       ; jmp to operator fn
  1842.    align           16
  1843. doneloop:
  1844.    ; NOTE: edx must be preserved here.
  1845.       mov          si,_PtrToZ          ; ds:si -> z
  1846.       mov          di,offset DGROUP:_new ; es:di -> new
  1847.       mov          cx,4
  1848.       rep          movsd               ; new = z
  1849.       mov          ax,es
  1850.       pop          di
  1851.       pop          si
  1852.       mov          ds,ax               ; restore ds before return
  1853.    assume          ds:DGROUP, es:nothing
  1854.       sub          _coloriter,edx      ; now put new coloriter back from edx
  1855.       ret
  1856. _fFormulaX         endp
  1857. ; --------------------------------------------------------------------------
  1858. ;    orbitcalc function follows
  1859. ; --------------------------------------------------------------------------
  1860.    public          _fFormula
  1861.    align           16
  1862. _fFormula          proc far
  1863.       push         di                  ; don't build a frame here
  1864.       mov          di,offset DGROUP:_s ; reset this for stk overflow area
  1865.       mov          bx,_InitOpPtr       ; bx -> one before first token
  1866.       mov          ax,ds               ; save ds in ax
  1867.       lds          cx,_fLastOp         ; ds:cx -> last token
  1868.       mov          es,ax               ; es -> DGROUP
  1869.    assume          es:DGROUP, ds:nothing
  1870.    align           16                  ; already aligned 16
  1871.       push         si                  ; 1-byte instruction
  1872. inner_loop:                            ; loop revised            CAE 09OCT93
  1873.       cmp          bx,cx               ; time to quit yet?
  1874.       jae          short past_loop     ; yes, bx points to last token
  1875.       add          bx,4                ; point to next token
  1876.       push         offset PARSERA_TEXT:inner_loop ; push return addr first
  1877.       mov          si,WORD PTR [bx+2]  ; now set si to operand pointer
  1878.       jmp          WORD PTR [bx]       ; ...and jump to operator fn
  1879. past_loop:                             ; 15-byte loop
  1880.    ; NOTE: AX was set by the last operator fn called.
  1881.       mov          si,_PtrToZ          ; ds:si -> z
  1882.       mov          di,offset DGROUP:_new ; es:di -> new
  1883.       mov          cx,4                ; get ready to move 4 dwords
  1884.       rep          movsd               ; new = z
  1885.       mov          bx,es               ; put seg dgroup in bx
  1886.       pop          si
  1887.       pop          di                  ; restore si, di
  1888.       mov          ds,bx               ; restore ds from bx before return
  1889.    assume          ds:DGROUP, es:nothing
  1890.       ret                              ; return AX unmodified
  1891. _fFormula          endp
  1892. ; --------------------------------------------------------------------------
  1893.    public          _fform_per_pixel    ; called once per pixel
  1894.    align           4
  1895. _fform_per_pixel   proc far
  1896.       FRAME        <si, di>
  1897.       cmp          _invert,0            ; inversion support added
  1898.       je           skip_invert          ;                        CAE 08FEB95
  1899.       mov          si,offset DGROUP:_old
  1900.       push         si
  1901.       call         far ptr _invertz2
  1902.       add          sp,2
  1903.       ; now copy old to v[0].a.d
  1904.       les          di,_v                ; ds:si already points to old
  1905.       add          di,CPFX              ; make es:di point to v[0].a.d
  1906.       mov          cx,4
  1907.       rep          movsd
  1908.       jmp          after_load
  1909. skip_invert:
  1910.    ;   /* v[5].a.d.x = */ (v[0].a.d.x = dx0[col]+dShiftx);
  1911.       mov          ax,_col
  1912.       shl          ax,3
  1913.       les          bx,_dx0
  1914.       add          bx,ax
  1915.       fld          QWORD PTR es:[bx]
  1916.       mov          ax,_row
  1917.       shl          ax,3
  1918.       les          bx,_dx1
  1919.       add          bx,ax
  1920.       fadd         QWORD PTR es:[bx]
  1921.       les          bx,_v
  1922.       fstp         QWORD PTR es:[bx+CPFX]
  1923.    ;   /* v[5].a.d.x = */ (v[0].a.d.y = dy0[row]+dShifty);
  1924.       mov          ax,_row
  1925.       shl          ax,3
  1926.       les          bx,_dy0
  1927.       add          bx,ax
  1928.       fld          QWORD PTR es:[bx]
  1929.       mov          ax,_col
  1930.       shl          ax,3
  1931.       les          bx,_dy1
  1932.       add          bx,ax
  1933.       fadd         QWORD PTR es:[bx]
  1934.       les          bx,_v
  1935.       fstp         QWORD PTR es:[bx+CPFX+8] ; make this an fstp
  1936. after_load:
  1937.       mov          di,offset DGROUP:_s ; di points to stack overflow area
  1938.       mov          ax,ds
  1939.       mov          bx,WORD PTR _pfls   ; bx -> pfls
  1940.       lds          cx,_fLastOp         ; cx = offset &f[LastOp],load ds
  1941.       mov          es,ax
  1942.    assume          es:DGROUP, ds:nothing
  1943.       cmp          _LastInitOp,0
  1944.       je           short skip_initloop ; no operators to do here
  1945.       mov          _LastInitOp,cx      ; lastinitop=lastop
  1946.       jmp          short pixel_loop
  1947.    align           16
  1948. pixel_loop:
  1949.       mov          si,WORD PTR [bx+2]  ; get address of load or store
  1950.       call         WORD PTR [bx]       ; (*opptr)()
  1951.       add          bx,4                ; ++opptr
  1952.       cmp          bx,_LastInitOp
  1953.       jb           short pixel_loop
  1954. skip_initloop:
  1955.       mov          si,_PtrToZ          ; ds:si -> z
  1956.       mov          di,offset DGROUP:_old ; es:di -> old
  1957.       mov          cx,4                ; get ready to move 4 dwords
  1958.       rep          movsd               ; old = z
  1959.       mov          ax,es
  1960.       mov          ds,ax
  1961.    assume          ds:DGROUP, es:nothing ; for the rest of the program
  1962.       sub          bx,4                ; make initopptr point 1 token b4 1st
  1963.       mov          _InitOpPtr, bx      ; InitOptPtr = OpPtr;
  1964.       UNFRAME      <di, si>
  1965.       xor          ax,ax
  1966.       ret
  1967. _fform_per_pixel   endp
  1968. ; --------------------------------------------------------------------------
  1969.  
  1970.    else  ; Compiler
  1971.  
  1972. ; --------------------------------------------------------------------------
  1973. ; . . . and now for the real fun!
  1974. ; --------------------------------------------------------------------------
  1975.    public          _Img_Setup
  1976.    align           2
  1977. _Img_Setup         proc far
  1978.       mov          ax,word ptr _v      ; build a ptr to Z
  1979.       add          ax,3*CARG+CPFX
  1980.       mov          _PtrToZ,ax          ; and save it
  1981.       ret
  1982. _Img_Setup         endp
  1983. ; --------------------------------------------------------------------------
  1984. ;  Hybrid orbitcalc/per-pixel routine.
  1985. ; --------------------------------------------------------------------------
  1986.    public          _fFormulaX
  1987.    align           16
  1988. _fFormulaX         proc far
  1989.       push         si
  1990.       push         di
  1991.       mov          edx,_maxit          ; edx holds coloriter during loop
  1992.       mov          _coloriter,edx      ; set coloriter to maxit
  1993.       mov          ax,ds               ; save ds in ax
  1994.       mov          cx,word ptr _pfls+2 ; just get the seg part
  1995.       mov          es,ax               ; es -> DGROUP
  1996.       mov          ds,cx               ; ds -> parser data
  1997.    assume          es:DGROUP, ds:nothing
  1998.       jmp          short skipfirst     ; skip bailout test first time
  1999.    align           16
  2000. outer_loop:
  2001.       or           ax,ax               ; did bailout occur?
  2002.       jnz          short doneloop      ; yes, exit
  2003. skipfirst:
  2004.       dec          edx                 ; ++coloriter, was maxiter reached?
  2005.       jle          short doneloop      ; yes, exit because of maxiter
  2006.       push         offset PARSERA_TEXT:outer_loop
  2007.       mov          di,offset DGROUP:_s ; reset this for stk overflow area
  2008.       jmp          _compiled_fn_2      ; call the compiled code
  2009. doneloop:
  2010.    ; NOTE: edx must be preserved here.
  2011.       mov          si,_PtrToZ          ; ds:si -> z
  2012.       mov          di,offset DGROUP:_new ; es:di -> new
  2013.       mov          cx,4
  2014.       rep          movsd               ; new = z
  2015.       mov          ax,es
  2016.       pop          di
  2017.       pop          si
  2018.       mov          ds,ax               ; restore ds before return
  2019.    assume          ds:DGROUP, es:nothing
  2020.       sub          _coloriter,edx      ; now put new coloriter back from edx
  2021.       ret
  2022. _fFormulaX         endp
  2023. ; --------------------------------------------------------------------------
  2024. ;    orbitcalc function follows
  2025. ; --------------------------------------------------------------------------
  2026.    public          _fFormula
  2027.    align           16
  2028. _fFormula          proc far
  2029.       push         di                  ; don't build a frame here
  2030.       mov          di,offset DGROUP:_s ; reset this for stk overflow area
  2031.       mov          ax,ds               ; save ds in ax
  2032.       mov          cx,WORD PTR _pfls+2 ; just load seg value
  2033.       mov          es,ax               ; es -> DGROUP
  2034.       mov          ds,cx               ; ds -> parser data
  2035.    assume          es:DGROUP, ds:nothing
  2036.       push         si                  ; compiled_fn modifies si
  2037.       call         _compiled_fn_2      ; call the compiled code
  2038.    ; NOTE: AX was set by the compiled code and must be preserved here.
  2039.       mov          si,_PtrToZ          ; ds:si -> z
  2040.       mov          di,offset DGROUP:_new ; es:di -> new
  2041.       mov          cx,4                ; get ready to move 4 dwords
  2042.       rep          movsd               ; new = z
  2043.       mov          bx,es               ; put seg dgroup in bx
  2044.       pop          si
  2045.       pop          di                  ; restore si, di
  2046.       mov          ds,bx               ; restore ds from bx before return
  2047.    assume          ds:DGROUP, es:nothing
  2048.       ret                              ; return AX unmodified
  2049. _fFormula          endp
  2050. ; --------------------------------------------------------------------------
  2051.    public          _fform_per_pixel    ; called once per pixel
  2052.    align           4
  2053. _fform_per_pixel   proc far
  2054.       FRAME        <si, di>
  2055.       cmp          _invert,0            ; inversion support added
  2056.       je           skip_invert          ;                        CAE 08FEB95
  2057.       mov          si,offset DGROUP:_old
  2058.       push         si
  2059.       call         far ptr _invertz2
  2060.       add          sp,2
  2061.       ; now copy old to v[0].a.d
  2062.       les          di,_v                ; ds:si already points to old
  2063.       add          di,CPFX              ; make es:di point to v[0].a.d
  2064.       mov          cx,4
  2065.       rep          movsd
  2066.       jmp          after_load
  2067. skip_invert:
  2068.    ;   /* v[5].a.d.x = */ (v[0].a.d.x = dx0[col]+dShiftx);
  2069.       mov          ax,_col
  2070.       shl          ax,3
  2071.       les          bx,_dx0
  2072.       add          bx,ax
  2073.       fld          QWORD PTR es:[bx]
  2074.       mov          ax,_row
  2075.       shl          ax,3
  2076.       les          bx,_dx1
  2077.       add          bx,ax
  2078.       fadd         QWORD PTR es:[bx]
  2079.       les          bx,_v
  2080.       fstp         QWORD PTR es:[bx+CPFX]
  2081.    ;   /* v[5].a.d.x = */ (v[0].a.d.y = dy0[row]+dShifty);
  2082.       mov          ax,_row
  2083.       shl          ax,3
  2084.       les          bx,_dy0
  2085.       add          bx,ax
  2086.       fld          QWORD PTR es:[bx]
  2087.       mov          ax,_col
  2088.       shl          ax,3
  2089.       les          bx,_dy1
  2090.       add          bx,ax
  2091.       fadd         QWORD PTR es:[bx]
  2092.       les          bx,_v
  2093.       fstp         QWORD PTR es:[bx+CPFX+8] ; make this an fstp
  2094. after_load:
  2095.       mov          di,offset DGROUP:_s ; di points to stack overflow area
  2096.       mov          ax,ds
  2097.       mov          cx,word ptr _pfls+2 ; just to load ds
  2098.       mov          es,ax               ; es -> DGROUP
  2099.       mov          ds,cx               ; ds -> parser data
  2100.    assume          es:DGROUP, ds:nothing
  2101.       call         _compiled_fn_1      ; call compiled code
  2102.       mov          ax,es
  2103.       mov          ds,ax
  2104.    assume          ds:DGROUP, es:nothing ; for the rest of the program
  2105.       UNFRAME      <di, si>
  2106.       xor          ax,ax
  2107.       ret
  2108. _fform_per_pixel   endp
  2109.  
  2110.    align           16
  2111.    public          _compiled_fn_1
  2112. _compiled_fn_1     proc near
  2113.       retn                             ; compiled code will be put here
  2114.       db           1023 DUP (?)
  2115. _compiled_fn_1     endp
  2116.  
  2117.    align           16
  2118.    public          _compiled_fn_2
  2119. _compiled_fn_2     proc near
  2120.       retn                             ; ...and here
  2121.       db           1023 DUP (?)
  2122. _compiled_fn_2     endp
  2123. ; --------------------------------------------------------------------------
  2124.  
  2125.    endif  ; COMPILER
  2126.  
  2127. ; --------------------------------------------------------------------------
  2128.  
  2129.  
  2130. PARSERA_TEXT      ends
  2131.    end
  2132.